diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,3 +1,7 @@
+## 0.4.26
+
+* Make sure we never read from or write to closed socket [#170](https://github.com/snoyberg/http-client/pull/170)
+
 ## 0.4.25
 
 * Don't error out when response body flushing fails [#169](https://github.com/snoyberg/http-client/issues/169)
diff --git a/Network/HTTP/Client/Connection.hs b/Network/HTTP/Client/Connection.hs
--- a/Network/HTTP/Client/Connection.hs
+++ b/Network/HTTP/Client/Connection.hs
@@ -85,15 +85,39 @@
                -> IO Connection
 makeConnection r w c = do
     istack <- newIORef []
+
+    -- it is necessary to make sure we never read from or write to
+    -- already closed connection.
+    closedVar <- newIORef False
+
     _ <- mkWeakIORef istack c
     return $! Connection
-        { connectionRead = join $ atomicModifyIORef istack $ \stack ->
-            case stack of
-                x:xs -> (xs, return x)
-                [] -> ([], r)
-        , connectionUnread = \x -> atomicModifyIORef istack $ \stack -> (x:stack, ())
-        , connectionWrite = w
-        , connectionClose = c
+        { connectionRead = do
+            closed <- readIORef closedVar
+            when closed $
+              throwIO ConnectionClosed
+            join $ atomicModifyIORef istack $ \stack ->
+              case stack of
+                  x:xs -> (xs, return x)
+                  [] -> ([], r)
+
+        , connectionUnread = \x -> do
+            closed <- readIORef closedVar
+            when closed $
+              throwIO ConnectionClosed
+            atomicModifyIORef istack $ \stack -> (x:stack, ())
+
+        , connectionWrite = \x -> do
+            closed <- readIORef closedVar
+            when closed $
+              throwIO ConnectionClosed
+            w x
+
+        , connectionClose = do
+            closed <- readIORef closedVar
+            unless closed $
+              c
+            writeIORef closedVar True
         }
 
 socketConnection :: Socket -> Int -> IO Connection
diff --git a/Network/HTTP/Client/Core.hs b/Network/HTTP/Client/Core.hs
--- a/Network/HTTP/Client/Core.hs
+++ b/Network/HTTP/Client/Core.hs
@@ -218,12 +218,10 @@
                 -- instead just close the connection.
                 let maxFlush = 1024
                 lbs <- brReadSome (responseBody res) maxFlush
-                    -- Ignore IO exceptions at this point. A server may
-                    -- terminate the connection immediately in some cases, such
-                    -- as when using withResponseHistory (where the response
-                    -- body may be flushed before getting this far). See:
+                    -- The connection may already be closed, e.g.
+                    -- when using withResponseHistory. See
                     -- https://github.com/snoyberg/http-client/issues/169
-                    `catch` \(_ :: IOException) -> return L.empty
+                    `catch` \(_ :: ConnectionClosed) -> return L.empty
                 responseClose res
 
                 -- And now perform the actual redirect
diff --git a/Network/HTTP/Client/Types.hs b/Network/HTTP/Client/Types.hs
--- a/Network/HTTP/Client/Types.hs
+++ b/Network/HTTP/Client/Types.hs
@@ -7,6 +7,7 @@
     ( BodyReader
     , Connection (..)
     , StatusHeaders (..)
+    , ConnectionClosed (..)
     , HttpException (..)
     , Cookie (..)
     , CookieJar (..)
@@ -75,11 +76,19 @@
     , connectionWrite :: S.ByteString -> IO ()
       -- ^ Send data to server
     , connectionClose :: IO ()
+      -- ^ Close connection. Any successive operation on the connection
+      -- (exept closing) should fail with `ConnectionClosed` exception.
+      -- It is allowed to close connection multiple times.
     }
     deriving T.Typeable
 
 data StatusHeaders = StatusHeaders Status HttpVersion RequestHeaders
     deriving (Show, Eq, Ord, T.Typeable)
+
+data ConnectionClosed = ConnectionClosed
+  deriving (Eq, Show)
+
+instance Exception ConnectionClosed
 
 data HttpException = StatusCodeException Status ResponseHeaders CookieJar
                    | InvalidUrlException String String
diff --git a/http-client.cabal b/http-client.cabal
--- a/http-client.cabal
+++ b/http-client.cabal
@@ -1,5 +1,5 @@
 name:                http-client
-version:             0.4.25
+version:             0.4.26
 synopsis:            An HTTP client engine, intended as a base layer for more user-friendly packages.
 description:         Hackage documentation generation is not reliable. For up to date documentation, please see: <http://www.stackage.org/package/http-client>.
 homepage:            https://github.com/snoyberg/http-client
diff --git a/test-nonet/Network/HTTP/ClientSpec.hs b/test-nonet/Network/HTTP/ClientSpec.hs
--- a/test-nonet/Network/HTTP/ClientSpec.hs
+++ b/test-nonet/Network/HTTP/ClientSpec.hs
@@ -1,9 +1,11 @@
 {-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ScopedTypeVariables #-}
 module Network.HTTP.ClientSpec where
 
 import           Control.Concurrent        (forkIO, threadDelay)
 import           Control.Concurrent.Async  (withAsync)
-import           Control.Exception         (bracket)
+import qualified Control.Concurrent.Async  as Async
+import           Control.Exception         (bracket, catch, IOException)
 import           Control.Monad             (forever, replicateM_, void)
 import           Network.HTTP.Client
 import           Network.HTTP.Types        (status413)
@@ -33,6 +35,20 @@
             N.appWrite ad "hello\r\n"
             threadDelay 10000
 
+redirectCloseServer :: (Int -> IO a) -> IO a
+redirectCloseServer inner = bracket
+    (N.bindRandomPortTCP "*4")
+    (sClose . snd)
+    $ \(port, lsocket) -> withAsync
+        (N.runTCPServer (N.serverSettingsTCPSocket lsocket) app)
+        (const $ inner port)
+  where
+    app ad = do
+      Async.race_
+          (forever (N.appRead ad))
+          (N.appWrite ad "HTTP/1.1 301 Redirect\r\nLocation: /\r\nConnection: close\r\n\r\nhello")
+      N.appCloseConnection ad
+
 bad100Server :: Bool -- ^ include extra headers?
              -> (Int -> IO a) -> IO a
 bad100Server extraHeaders inner = bracket
@@ -175,3 +191,14 @@
         withManager defaultManagerSettings $ \man -> do
             res <- getChunkedResponse port' man
             responseBody res `shouldBe` "Wikipedia in\r\n\r\nchunks."
+
+    it "withResponseHistory and redirect" $ redirectCloseServer $ \port -> do
+        -- see https://github.com/snoyberg/http-client/issues/169
+        req' <- parseUrl $ "http://127.0.0.1:" ++ show port
+        let req = req' {redirectCount = 1}
+        withManager defaultManagerSettings $ \man -> do
+          withResponseHistory req man (const $ return ())
+            `shouldThrow` \e ->
+              case e of
+                TooManyRedirects _ -> True
+                _ -> False
