diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,10 @@
 # ChangeLog for warp
 
+## 3.3.17
+
+* Modify exception handling to swallow async exceptions in forked thread [#850](https://github.com/yesodweb/wai/issues/850)
+* Switch default forking function to not install the global exception handler (minor optimization) [#851](https://github.com/yesodweb/wai/pull/851)
+
 ## 3.3.16
 
 * Move exception handling over to `unliftio` for better async exception support [#845](https://github.com/yesodweb/wai/issues/845)
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
@@ -9,6 +9,7 @@
 
 import Control.Arrow (first)
 import Control.Exception (allowInterrupt)
+import qualified Control.Exception
 import qualified UnliftIO
 import UnliftIO (toException)
 import qualified Data.ByteString as S
@@ -288,7 +289,12 @@
 fork set mkConn addr app counter ii = settingsFork set $ \unmask ->
     -- Call the user-supplied on exception code if any
     -- exceptions are thrown.
-    UnliftIO.handleAny (settingsOnException set Nothing) $
+    --
+    -- Intentionally using Control.Exception.handle, since we want to
+    -- catch all exceptions and avoid them from propagating, even
+    -- async exceptions. See:
+    -- https://github.com/yesodweb/wai/issues/850
+    Control.Exception.handle (settingsOnException set Nothing) $
         -- Run the connection maker to get a new connection, and ensure
         -- that the connection is closed. If the mkConn call throws an
         -- exception, we will leak the connection. If the mkConn call is
diff --git a/Network/Wai/Handler/Warp/Settings.hs b/Network/Wai/Handler/Warp/Settings.hs
--- a/Network/Wai/Handler/Warp/Settings.hs
+++ b/Network/Wai/Handler/Warp/Settings.hs
@@ -1,10 +1,12 @@
 {-# LANGUAGE OverloadedStrings, ScopedTypeVariables, ViewPatterns #-}
 {-# LANGUAGE PatternGuards, RankNTypes #-}
 {-# LANGUAGE ImpredicativeTypes, CPP #-}
+{-# LANGUAGE MagicHash, UnboxedTuples #-}
 
 module Network.Wai.Handler.Warp.Settings where
 
-import Control.Concurrent (forkIOWithUnmask)
+import GHC.IO (unsafeUnmask, IO (IO))
+import GHC.Prim (fork#)
 import UnliftIO (SomeException, fromException)
 import qualified Data.ByteString.Char8 as C8
 import qualified Data.ByteString.Builder as Builder
@@ -63,7 +65,7 @@
       -- This may be useful if you need OS bound threads, or if
       -- you wish to develop an alternative threading model.
       --
-      -- Default: void . forkIOWithUnmask
+      -- Default: 'defaultFork'
       --
       -- Since 3.0.4
 
@@ -163,7 +165,7 @@
     , settingsFdCacheDuration = 0
     , settingsFileInfoCacheDuration = 0
     , settingsBeforeMainLoop = return ()
-    , settingsFork = void . forkIOWithUnmask
+    , settingsFork = defaultFork
     , settingsNoParsePath = False
     , settingsInstallShutdownHandler = const $ return ()
     , settingsServerName = C8.pack $ "Warp/" ++ showVersion Paths_warp.version
@@ -236,3 +238,18 @@
     responseBuilder H.internalServerError500
                     [(H.hContentType, "text/plain; charset=utf-8")]
                     $ "Exception: " <> Builder.stringUtf8 (show e)
+
+-- | Similar to @forkIOWithUnmask@, but does not set up the default exception handler.
+--
+-- Since Warp will always install its own exception handler in forked threads, this provides
+-- a minor optimization.
+--
+-- For inspiration of this function, see @rawForkIO@ in the @async@ package.
+--
+-- @since 3.3.17
+defaultFork :: ((forall a. IO a -> IO a) -> IO ()) -> IO ()
+defaultFork io =
+  IO $ \s0 ->
+    case (fork# (io unsafeUnmask) s0) of
+      (# s1, _tid #) ->
+        (# s1, () #)
diff --git a/warp.cabal b/warp.cabal
--- a/warp.cabal
+++ b/warp.cabal
@@ -1,5 +1,5 @@
 Name:                warp
-Version:             3.3.16
+Version:             3.3.17
 Synopsis:            A fast, light-weight web server for WAI applications.
 License:             MIT
 License-file:        LICENSE
