diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,9 @@
 # Changelog for http-client
 
+## 0.7.12
+
+* Fix premature connection closing due to weak reference lifetimes [#490](https://github.com/snoyberg/http-client/pull/490)
+
 ## 0.7.11
 
 * Allow making requests to raw IPv6 hosts [#477](https://github.com/snoyberg/http-client/pull/477)
diff --git a/Network/HTTP/Client.hs b/Network/HTTP/Client.hs
--- a/Network/HTTP/Client.hs
+++ b/Network/HTTP/Client.hs
@@ -349,9 +349,9 @@
 -- >   -- Create the request
 -- >   let requestObject = object ["name" .= "Michael", "age" .= 30]
 -- >   let requestObject = object
--- >    [ "name" .= ("Michael" :: Text)
--- >    , "age"  .= (30 :: Int)
--- >    ]
+-- >        [ "name" .= ("Michael" :: Text)
+-- >        , "age"  .= (30 :: Int)
+-- >        ]
 -- >
 -- >   initialRequest <- parseRequest "http://httpbin.org/post"
 -- >   let request = initialRequest { method = "POST", requestBody = RequestBodyLBS $ encode requestObject }
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
@@ -210,7 +210,7 @@
 
 -- Pick up an IP using an approximation of the happy-eyeballs algorithm:
 -- https://datatracker.ietf.org/doc/html/rfc8305
--- 
+--
 firstSuccessful :: [NS.AddrInfo] -> (NS.AddrInfo -> IO a) -> IO a
 firstSuccessful []        _  = error "getAddrInfo returned empty list"
 firstSuccessful addresses cb = do
@@ -226,12 +226,12 @@
         z <- forConcurrently (zip addresses [0..]) $ \(addr, n) -> do
             when (n > 0) $ threadDelay $ n * connectionAttemptDelay
             tryAddress addr
-        
-        case listToMaybe (reverse z) of 
-            Just e@(Left _) -> tryPutMVar result e        
-            _               -> error $ "tryAddresses invariant violated: " <> show addresses
+
+        case listToMaybe (reverse z) of
+            Just e@(Left _) -> tryPutMVar result e
+            _               -> error $ "tryAddresses invariant violated: " ++ show addresses
       where
         tryAddress addr = do
             r :: Either E.IOException a <- E.try $! cb addr
             for_ r $ \_ -> tryPutMVar result r
-            pure r             
+            pure r
diff --git a/Network/HTTP/Client/Response.hs b/Network/HTTP/Client/Response.hs
--- a/Network/HTTP/Client/Response.hs
+++ b/Network/HTTP/Client/Response.hs
@@ -97,7 +97,14 @@
 
         -- should we put this connection back into the connection manager?
         toPut = Just "close" /= lookup "connection" hs && version > W.HttpVersion 1 0
-        cleanup bodyConsumed = managedRelease mconn $ if toPut && bodyConsumed then Reuse else DontReuse
+        cleanup bodyConsumed = do
+            managedRelease mconn $ if toPut && bodyConsumed then Reuse else DontReuse
+            -- Keep alive the `Managed Connection` until we're done with it, to prevent an early
+            -- collection.
+            -- Reasoning: as long as someone holds a reference to the explicit cleanup,
+            -- we shouldn't perform an implicit cleanup.
+            keepAlive mconn
+
 
     body <-
         -- RFC 2616 section 4.4_1 defines responses that must not include a body
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.7.11
+version:             0.7.12
 synopsis:            An HTTP client engine
 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/Network/HTTP/ClientSpec.hs b/test/Network/HTTP/ClientSpec.hs
--- a/test/Network/HTTP/ClientSpec.hs
+++ b/test/Network/HTTP/ClientSpec.hs
@@ -1,6 +1,7 @@
 {-# LANGUAGE OverloadedStrings #-}
 module Network.HTTP.ClientSpec where
 
+import           Control.Concurrent (threadDelay)
 import qualified Data.ByteString.Char8        as BS
 import           Network.HTTP.Client
 import           Network.HTTP.Client.Internal
@@ -10,6 +11,7 @@
 import           Test.Hspec
 import           Control.Applicative       ((<$>))
 import           Data.ByteString.Lazy.Char8 () -- orphan instance
+import           System.Mem (performGC)
 
 main :: IO ()
 main = hspec spec
@@ -21,6 +23,31 @@
         man <- newManager defaultManagerSettings
         res <- httpLbs req man
         responseStatus res `shouldBe` status200
+
+    -- Test the failure condition described in https://github.com/snoyberg/http-client/issues/489
+    it "keeps connection alive long enough" $ do
+        req <- parseUrlThrow "http://httpbin.org/"
+        man <- newManager defaultManagerSettings
+        res <- responseOpen req man
+        responseStatus res `shouldBe` status200
+        let
+            getChunk = responseBody res
+            drainAll = do
+                chunk <- getChunk
+                if BS.null chunk then pure () else drainAll
+
+        -- The returned `BodyReader` used to not contain a reference to the `Managed Connection`,
+        -- only to the extracted connection and to the release action. Therefore, triggering a GC
+        -- would close the connection even though we were not done reading.
+        performGC
+        -- Not ideal, but weak finalizers run on a separate thread, so it's racing with our drain
+        -- call
+        threadDelay 500000
+
+        drainAll
+        -- Calling `responseClose res` here prevents the early collection from happening in this
+        -- test, but in a larger production application that did involve a `responseClose`, it still
+        -- occurred.
 
     describe "method in URL" $ do
         it "success" $ do
