diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,16 @@
 # Revision history for network-run
 
+## 0.7.1
+
+* Sockets this library owns and has not handed to anyone are closed with
+  `close(2)` rather than with `close`, which goes through the IO manager
+  to tell a waiter that is not there.
+* `settingsUnsafeClose` lets a server close its connections with
+  `unsafeGracefulClose` or `unsafeClose`.  The default keeps `close`,
+  since only the caller knows whether its handler leaves a thread on the
+  socket.
+* Requires network 3.2.12.
+
 ## 0.7.0
 
 * The accept loop is stopped by being told, through the new
diff --git a/Network/Run/Core.hs b/Network/Run/Core.hs
--- a/Network/Run/Core.hs
+++ b/Network/Run/Core.hs
@@ -81,7 +81,7 @@
 -- The options are set before 'connect'.
 openClientSocketWithOpts
     :: [(SocketOption, SockOptValue)] -> AddrInfo -> IO Socket
-openClientSocketWithOpts opts addr = E.bracketOnError (openSocket addr) close $ \sock -> do
+openClientSocketWithOpts opts addr = E.bracketOnError (openSocket addr) unsafeClose $ \sock -> do
     mapM_ (uncurry $ setSockOptValue sock) opts
     connect sock $ addrAddress addr
     return sock
@@ -127,7 +127,7 @@
 -- cannot be cleared.
 openServerSocketWithOpts
     :: [(SocketOption, SockOptValue)] -> AddrInfo -> IO Socket
-openServerSocketWithOpts opts addr = E.bracketOnError (openSocket addr) close $ \sock -> do
+openServerSocketWithOpts opts addr = E.bracketOnError (openSocket addr) unsafeClose $ \sock -> do
     setSocketOption sock ReuseAddr 1
 #if !defined(openbsd_HOST_OS)
     when (addrFamily addr == AF_INET6) $ setSocketOption sock IPv6Only 1
@@ -206,6 +206,12 @@
     -- connection handler returns.  Zero or less uses 'close' instead,
     -- which releases the file descriptor immediately.  The default is
     -- 5000.
+    , settingsUnsafeClose :: Bool
+    -- ^ Closing a connected socket with 'unsafeGracefulClose' or
+    -- 'unsafeClose', which skip the IO manager that 'close' goes through
+    -- to tell a thread waiting on the socket.  Set this only when the
+    -- connection handler leaves no thread and no registered wait on the
+    -- socket by the time it returns.  The default is 'False'.
     , settingsAcceptRetryDelay :: Int
     -- ^ Microseconds to wait before retrying 'accept' after running
     -- out of file descriptors.  The default is 100000.
@@ -235,6 +241,7 @@
     ServerSettings
         { settingsOnException = \_ _ -> return ()
         , settingsGracefulCloseTimeout = 5000
+        , settingsUnsafeClose = False
         , settingsAcceptRetryDelay = 100000
         , settingsInstallShutdownHandler = const $ return ()
         }
@@ -253,8 +260,12 @@
 -- | Closing a connected socket according to the settings.
 gcloseWith :: ServerSettings -> Socket -> IO ()
 gcloseWith ServerSettings{..} sock
-    | settingsGracefulCloseTimeout <= 0 = close sock
-    | otherwise = gracefulClose sock settingsGracefulCloseTimeout
+    | settingsGracefulCloseTimeout <= 0 = closer sock
+    | otherwise = gracefulCloser sock settingsGracefulCloseTimeout
+  where
+    (closer, gracefulCloser)
+        | settingsUnsafeClose = (unsafeClose, unsafeGracefulClose)
+        | otherwise = (close, gracefulClose)
 
 ----------------------------------------------------------------
 
diff --git a/Network/Run/TCP.hs b/Network/Run/TCP.hs
--- a/Network/Run/TCP.hs
+++ b/Network/Run/TCP.hs
@@ -54,7 +54,7 @@
     -> IO ()
 runTCPServerWithSettings set mhost port server = do
     addr <- resolve Stream mhost port [AI_PASSIVE] NE.head
-    E.bracket (openTCPServerSocket addr) close $ \sock ->
+    E.bracket (openTCPServerSocket addr) unsafeClose $ \sock ->
         runTCPServerWithSocketAndSettings set sock server
 
 -- | Running a TCP server on a given listen socket.
@@ -83,7 +83,7 @@
     -- is closed if anything goes wrong before the thread owning it has
     -- been forked.
     loop listener = do
-        more <- E.bracketOnError (acceptOrStop listener) (mapM_ (close . fst)) $ \maccepted ->
+        more <- E.bracketOnError (acceptOrStop listener) (mapM_ (unsafeClose . fst)) $ \maccepted ->
             case maccepted of
                 Nothing -> return False
                 Just (conn, peer) -> do
diff --git a/Network/Run/TCP/Timeout.hs b/Network/Run/TCP/Timeout.hs
--- a/Network/Run/TCP/Timeout.hs
+++ b/Network/Run/TCP/Timeout.hs
@@ -59,7 +59,7 @@
     -> IO ()
 runTCPServerWithSettings set tm mhost port server = do
     addr <- resolve Stream mhost port [AI_PASSIVE] NE.head
-    E.bracket (openTCPServerSocket addr) close $ \sock ->
+    E.bracket (openTCPServerSocket addr) unsafeClose $ \sock ->
         runTCPServerWithSocketAndSettings set tm sock server
 
 -- | Running a TCP server on a given listen socket.
@@ -90,7 +90,7 @@
     -- is closed if anything goes wrong before the thread owning it has
     -- been forked.
     loop listener mgr = do
-        more <- E.bracketOnError (acceptOrStop listener) (mapM_ (close . fst)) $ \maccepted ->
+        more <- E.bracketOnError (acceptOrStop listener) (mapM_ (unsafeClose . fst)) $ \maccepted ->
             case maccepted of
                 Nothing -> return False
                 Just (conn, peer) -> do
diff --git a/Network/Run/UDP.hs b/Network/Run/UDP.hs
--- a/Network/Run/UDP.hs
+++ b/Network/Run/UDP.hs
@@ -101,7 +101,7 @@
             -- If 'connect' throws, the socket is closed here.  On
             -- success it is owned by the new thread and is closed by
             -- its finalizer.
-            E.bracketOnError (openServerSocket addr) close $ \s -> do
+            E.bracketOnError (openServerSocket addr) unsafeClose $ \s -> do
                 connect s peeraddr
                 forkDatagram set s peeraddr $
                     labelMe "UDP server" >> server s bs0
diff --git a/network-run.cabal b/network-run.cabal
--- a/network-run.cabal
+++ b/network-run.cabal
@@ -1,6 +1,6 @@
 cabal-version:      2.0
 name:               network-run
-version:            0.7.0
+version:            0.7.1
 license:            BSD3
 license-file:       LICENSE
 maintainer:         kazu@iij.ad.jp
@@ -31,7 +31,7 @@
     build-depends:
         base >=4 && <5,
         bytestring >=0.10 && <0.13,
-        network >=3.2.10 && <3.3,
+        network >=3.2.12 && <3.3,
         stm >=2.5 && <2.6,
         time-manager >=0.2 && <0.6
 
diff --git a/test/TCPSpec.hs b/test/TCPSpec.hs
--- a/test/TCPSpec.hs
+++ b/test/TCPSpec.hs
@@ -150,6 +150,26 @@
                     putMVar gate ()
                     recv sock 1024 `shouldThrow` anyIOException
 
+        it "drains a connection with unsafeGracefulClose when asked to" $ limited $ do
+            gate <- newEmptyMVar
+            let set = defaultServerSettings{settingsGracefulCloseTimeout = 500, settingsUnsafeClose = True}
+            withTCPServer set (\_ -> takeMVar gate) $ \port ->
+                client port $ \sock -> do
+                    sendAll sock "hello"
+                    threadDelay 200000
+                    putMVar gate ()
+                    recv sock 1024 `shouldReturn` ""
+
+        it "resets a connection with unsafeClose when asked to" $ limited $ do
+            gate <- newEmptyMVar
+            let set = defaultServerSettings{settingsGracefulCloseTimeout = 0, settingsUnsafeClose = True}
+            withTCPServer set (\_ -> takeMVar gate) $ \port ->
+                client port $ \sock -> do
+                    sendAll sock "hello"
+                    threadDelay 200000
+                    putMVar gate ()
+                    recv sock 1024 `shouldThrow` anyIOException
+
         it "serves many connections concurrently" $
             limited $
                 withTCPServer defaultServerSettings echo $ \port -> do
