diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,9 @@
 # ChangeLog
 
+## 0.2.7
+
+* Introducing `forkManaged` to manage readers of clients properly.
+
 ## 0.2.6
 
 * Using `ServerState` instead of `killThread`.
diff --git a/Network/QUIC/Client/Reader.hs b/Network/QUIC/Client/Reader.hs
--- a/Network/QUIC/Client/Reader.hs
+++ b/Network/QUIC/Client/Reader.hs
@@ -15,6 +15,7 @@
 import Network.Socket (Socket, close, getSocketName)
 import qualified Network.Socket.ByteString as NSB
 
+import Network.QUIC.Common
 import Network.QUIC.Connection
 import Network.QUIC.Connector
 import Network.QUIC.Crypto
@@ -30,6 +31,7 @@
 -- | readerClient dies when the socket is closed.
 readerClient :: Socket -> Connection -> IO ()
 readerClient s0 conn = handleLogUnit logAction $ do
+    labelMe "readerClient"
     wait
     loop
   where
@@ -146,5 +148,5 @@
     newSock <- natRebinding peersa
     oldSock <- setSocket conn newSock
     let reader = readerClient newSock conn
-    forkIO reader >>= addReader conn
+    forkManaged conn reader
     fire conn microseconds $ close oldSock
diff --git a/Network/QUIC/Client/Run.hs b/Network/QUIC/Client/Run.hs
--- a/Network/QUIC/Client/Run.hs
+++ b/Network/QUIC/Client/Run.hs
@@ -7,7 +7,6 @@
     migrate,
 ) where
 
-import Control.Concurrent
 import Control.Concurrent.Async
 import qualified Control.Exception as E
 import qualified Network.Socket as NS
@@ -58,7 +57,7 @@
 runClient :: ClientConfig -> (Connection -> IO a) -> Bool -> VersionInfo -> IO a
 runClient conf client0 isICVN verInfo = do
     E.bracket open clse $ \(ConnRes conn myAuthCIDs reader) -> do
-        forkIO reader >>= addReader conn
+        forkManaged conn reader
         let conf' =
                 conf
                     { ccParameters =
diff --git a/Network/QUIC/Connection/Misc.hs b/Network/QUIC/Connection/Misc.hs
--- a/Network/QUIC/Connection/Misc.hs
+++ b/Network/QUIC/Connection/Misc.hs
@@ -21,7 +21,7 @@
     delayedAck,
     resetDealyedAck,
     setMaxPacketSize,
-    addReader,
+    forkManaged,
     killReaders,
     addResource,
     freeResources,
@@ -35,6 +35,7 @@
 
 import Control.Concurrent
 import qualified Control.Exception as E
+import qualified Data.Map.Strict as Map
 import Network.Socket (Socket)
 import System.Mem.Weak
 
@@ -161,12 +162,32 @@
 addReader :: Connection -> ThreadId -> IO ()
 addReader Connection{..} tid = do
     wtid <- mkWeakThreadId tid
-    atomicModifyIORef'' readers $ \m -> do
-        m
-        deRefWeak wtid >>= mapM_ killThread
+    let n = fromThreadId tid
+    atomicModifyIORef'' readers $ Map.insert n wtid
 
+delReader :: Connection -> ThreadId -> IO ()
+delReader Connection{..} tid = do
+    let n = fromThreadId tid
+    atomicModifyIORef'' readers $ Map.delete n
+
+forkManaged :: Connection -> IO () -> IO ()
+forkManaged conn action = void $ forkIO $ do
+    E.bracket setup clean $ \_ -> action
+  where
+    setup = do
+        tid <- myThreadId
+        addReader conn tid
+        return tid
+    clean = delReader conn
+
 killReaders :: Connection -> IO ()
-killReaders Connection{..} = join $ readIORef readers
+killReaders Connection{..} = do
+    wtids <- readIORef readers
+    forM_ wtids $ \wtid -> do
+        mtid <- deRefWeak wtid
+        case mtid of
+            Nothing -> return ()
+            Just tid -> killThread tid
 
 ----------------------------------------------------------------
 
diff --git a/Network/QUIC/Connection/Types.hs b/Network/QUIC/Connection/Types.hs
--- a/Network/QUIC/Connection/Types.hs
+++ b/Network/QUIC/Connection/Types.hs
@@ -20,6 +20,7 @@
 import Network.Control (Rate, RxFlow, TxFlow, newRate, newRxFlow, newTxFlow)
 import Network.Socket (Cmsg, SockAddr, Socket)
 import Network.TLS.QUIC
+import System.Mem.Weak (Weak)
 
 import Network.QUIC.Config
 import Network.QUIC.Connector
@@ -202,7 +203,7 @@
     -- Manage
     , connRecvQ :: RecvQ
     , connSocket :: IORef Socket
-    , readers :: IORef (IO ())
+    , readers :: IORef (Map Word64 (Weak ThreadId))
     , mainThreadId :: ThreadId
     , controlRate :: Rate
     , -- Info
@@ -306,7 +307,7 @@
     ecrptBuf <- mallocBytes bufsiz
     dcrptBuf <- mallocBytes bufsiz
     Connection connstate debugLog qLog hooks send recv recvQ sref
-        <$> newIORef (return ())
+        <$> newIORef Map.empty
         <*> myThreadId
         <*> newRate
         -- Info
diff --git a/Network/QUIC/Imports.hs b/Network/QUIC/Imports.hs
--- a/Network/QUIC/Imports.hs
+++ b/Network/QUIC/Imports.hs
@@ -25,6 +25,7 @@
 #endif
     atomicModifyIORef'',
     copyBS,
+    fromThreadId,
 ) where
 
 import Control.Applicative
@@ -49,6 +50,12 @@
 import Network.QUIC.Utils
 import Numeric
 
+#if __GLASGOW_HASKELL__ >= 908
+import GHC.Conc.Sync (fromThreadId)
+#else
+import Control.Concurrent (ThreadId)
+#endif
+
 -- | All internal byte sequences.
 --   `ByteString` should be used for FFI related stuff.
 type Bytes = ShortByteString
@@ -71,3 +78,8 @@
     let src = src0 `plusPtr` off
     copyBytes dst src len
     return len
+
+#if __GLASGOW_HASKELL__ < 908
+fromThreadId :: ThreadId -> Word64
+fromThreadId tid = read (drop 9 $ show tid)
+#endif
diff --git a/quic.cabal b/quic.cabal
--- a/quic.cabal
+++ b/quic.cabal
@@ -1,6 +1,6 @@
 cabal-version:      >=1.10
 name:               quic
-version:            0.2.6
+version:            0.2.7
 license:            BSD3
 license-file:       LICENSE
 maintainer:         kazu@iij.ad.jp
diff --git a/test/IOSpec.hs b/test/IOSpec.hs
--- a/test/IOSpec.hs
+++ b/test/IOSpec.hs
@@ -89,6 +89,9 @@
     describe "concurrency" $ do
         it "can handle multiple clients" $ do
             withPipe (Randomly 20) $ testMultiSendRecv cc sc waitS 500
+    describe "abortConnection" $ do
+        it "can abort connection" $ do
+            withPipe (Randomly 20) $ testAbort cc sc waitS
 
 consumeBytes :: Stream -> Int -> IO ()
 consumeBytes _ 0 = return ()
@@ -200,4 +203,31 @@
                 consumeBytes strm (chunklen * times)
                 assertEndOfStream strm
                 putMVar (mvars !! n) ()
+            loop conn
+
+appErr :: QUICException -> Bool
+appErr (ApplicationProtocolErrorIsReceived _ _) = True
+appErr _ = False
+
+testAbort :: C.ClientConfig -> ServerConfig -> IO () -> IO ()
+testAbort cc sc waitS = do
+    E.bracket (forkIO server) killThread $ \_ ->
+        client `shouldThrow` appErr
+  where
+    client = do
+        waitS
+        C.run cc $ \conn -> do
+            strm <- stream conn
+            sendStream strm "foo"
+            void $ recvStream strm 10
+    server = run sc loop
+      where
+        loop conn = do
+            _strm <- acceptStream conn
+            void $
+                forkIO $
+                    abortConnection
+                        conn
+                        (ApplicationProtocolError 1)
+                        "testing abortConnection"
             loop conn
