diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,64 +1,73 @@
 # ChangeLog for warp
 
+## 3.4.20
+
+* Building with GHC 9.0 again.
+  [#1161](https://github.com/yesodweb/wai/issues/1161)
+
 ## 3.4.19
 
 * Security: `Host` is validated.  A HTTP/1.1 request without one, and any
   request with more than one, is refused: a router reading the first and an
   application reading `requestHeaderHost` could disagree about which host a
   request was for.
+  [#1152](https://github.com/yesodweb/wai/issues/1152)
 * Security: a `Range` which does not begin inside the file is answered 416,
   rather than dropping the connection with no answer at all.
+  [#1153](https://github.com/yesodweb/wai/issues/1153)
 * Security: `packIntegral` counts its digits by division.  The `Double`
   logarithm it used was one short from 10^15 up, and the last digit was
   written before the buffer.
+  [#1154](https://github.com/yesodweb/wai/issues/1154)
 * Security: the HTTP/2 connection a GOAWAY for weak TLS ends is no longer
   served afterwards, and that GOAWAY now follows the SETTINGS frame which
   RFC 9113 has a server send first.
+  [#1155](https://github.com/yesodweb/wai/issues/1155)
 * Security: the HTTP/2 `response` continuation is not called a second time
   when an application throws after its response has gone out.
+  [#1156](https://github.com/yesodweb/wai/issues/1156)
 * `InvalidRequest` gains `BadHost`.
-* Header field names are validated by a lookup table rather than by a chain
-  of range tests.
+  [#1152](https://github.com/yesodweb/wai/issues/1152)
+* Validate field names with a lookup table.
+  [#1157](https://github.com/yesodweb/wai/issues/1157)
 
 ## 3.4.18
 
-* The accept loop is stopped by being told, through the new
-  `settingsInstallShutdownHandler`, rather than by having the listening
-  socket closed under it, and the graceful shutdown's receive is one
-  `receiveWith`.  Nothing is closed and no thread is interrupted to make
-  either of them return: a close ends a thread blocked on a descriptor
-  only because the event manager says so, which GHC is removing, and an
-  asynchronous exception does not reach a thread blocked in a socket call
-  on Windows -- where, before this, a server could not be stopped at all.
-  [#1136](https://github.com/yesodweb/wai/issues/1136)
-* The threads serving connections are owned by a thread manager, so a
-  killed server no longer leaves them running, and a connection which has
-  been accepted but not yet scheduled is counted by `gracefulShutdown`
-  rather than being invisible to it.
-  [#1126](https://github.com/yesodweb/wai/issues/1126)
-  [#1132](https://github.com/yesodweb/wai/issues/1132)
-* `Internal` exports `Listener (..)`, `noListener`, `makeListener`,
-  `AcceptStopped (..)` and `runSettingsConnectionMakerSecureWith`.
-* Requires network 3.2.10, recv 0.1.3 and time-manager 0.5.
+`Internal` gains `Listener (..)`, `noListener`, `makeListener`,
+`AcceptStopped (..)` and `runSettingsConnectionMakerSecureWith`.  Requires
+network 3.2.10, recv 0.1.3 and time-manager 0.5.
 
+* Event poll for accept loop.
+  [#1123](https://github.com/yesodweb/wai/pull/1123)
+* Give up on the accept and the receive rather than interrupt them.
+  [#1143](https://github.com/yesodweb/wai/pull/1143)
+* recv: a receive the caller can give up on.
+  [#1142](https://github.com/yesodweb/wai/pull/1142)
+* warp: let the thread manager own the connections.
+  [#1128](https://github.com/yesodweb/wai/pull/1128)
+
 ## 3.4.17
 
 * Security: `Transfer-Encoding` is read as the comma separated list RFC 9112
   defines, and a framing warp and a proxy could read differently is refused.
+  [#1147](https://github.com/yesodweb/wai/issues/1147)
 * Security: a `Content-Length` must be digits which fit in an `Int` and
   repeated ones must agree.
+  [#1148](https://github.com/yesodweb/wai/issues/1148)
 * Security: a header field name must be a non-empty token, which also refuses
   obs-fold continuation lines.
+  [#1149](https://github.com/yesodweb/wai/issues/1149)
 * Security: a bare CR or a NUL in a header field line is refused.
+  [#1151](https://github.com/yesodweb/wai/issues/1151)
 * Security: the chunked body parser keeps to RFC 9112: chunk sizes, the CRLF
   after a chunk, size lines split over several reads, and the trailer section.
-* A chunked body cut short by the end of input is now an error rather than a
-  body the application is handed as though it were whole.
-  [#1129](https://github.com/yesodweb/wai/issues/1129).
-* A last chunk must now be followed by the CRLF which ends the trailer
-  section, unless the connection ends there.
+  [#1150](https://github.com/yesodweb/wai/issues/1150)
+* warp: a chunked request body cut off mid-chunk reaches the application as
+  complete.
+  [#1129](https://github.com/yesodweb/wai/issues/1129)
 * `InvalidRequest` gains `UnsupportedTransferEncoding`, `AmbiguousBodyLength`,
-  `BadFieldName`, `BadHeaderLine` and `BadChunkedBody`.
+  `BadFieldName`, `BadHeaderLine` and `BadChunkedBody`, one for each of the
+  five above.
 * Allow time-manager 0.5.
 
 ## 3.4.16
diff --git a/Network/Wai/Handler/Warp/Run.hs b/Network/Wai/Handler/Warp/Run.hs
--- a/Network/Wai/Handler/Warp/Run.hs
+++ b/Network/Wai/Handler/Warp/Run.hs
@@ -486,7 +486,9 @@
     -- scheduled, so counting there leaves a window in which the connection
     -- is accepted and not counted, and 'gracefulShutdown' waits on this
     -- counter.
-    forkConnection counter (settingsFork set) runConnection
+    -- Eta-expanded so that GHC 9.0, which lacks deep subsumption, accepts
+    -- 'runConnection' at the rank-2 type.
+    forkConnection counter (settingsFork set) (\unmask -> runConnection unmask)
   where
     runConnection unmask =
         -- Call the user-supplied on exception code if any
diff --git a/warp.cabal b/warp.cabal
--- a/warp.cabal
+++ b/warp.cabal
@@ -1,6 +1,6 @@
 cabal-version:      >=1.10
 name:               warp
-version:            3.4.19
+version:            3.4.20
 license:            MIT
 license-file:       LICENSE
 maintainer:         michael@snoyman.com
