diff --git a/hasbolt.cabal b/hasbolt.cabal
--- a/hasbolt.cabal
+++ b/hasbolt.cabal
@@ -1,5 +1,5 @@
 name: hasbolt
-version: 0.1.0.8
+version: 0.1.0.9
 cabal-version: >=1.10
 build-type: Simple
 license: BSD3
@@ -63,7 +63,7 @@
     main-is: Spec.hs
     build-depends:
         base >=4.9.0.0 && <4.10,
-        hasbolt >=0.1.0.8 && <0.2,
+        hasbolt >=0.1.0.9 && <0.2,
         hspec >=2.2.4 && <2.3,
         QuickCheck >=2.8.2 && <2.9,
         hex >=0.1.2 && <0.2,
diff --git a/src/Database/Bolt/Connection.hs b/src/Database/Bolt/Connection.hs
--- a/src/Database/Bolt/Connection.hs
+++ b/src/Database/Bolt/Connection.hs
@@ -30,7 +30,7 @@
                           if isSuccess status then do flush pipe RequestPullAll
                                                       (status:) <$> pullRest pipe
                                               else do ackFailure pipe
-                                                      return [status]
+                                                      mkFailure status
 
         pullRest :: MonadIO m => Pipe -> m [Response]
         pullRest pipe = do resp <- fetch pipe
diff --git a/src/Database/Bolt/Connection/Pipe.hs b/src/Database/Bolt/Connection/Pipe.hs
--- a/src/Database/Bolt/Connection/Pipe.hs
+++ b/src/Database/Bolt/Connection/Pipe.hs
@@ -8,10 +8,10 @@
 import           Database.Bolt.Value.Type
 
 import           Control.Monad                      (forM_, unless, void, when)
-import           Control.Monad.IO.Class             (MonadIO (..), liftIO)
+import           Control.Monad.IO.Class             (MonadIO (..))
 import           Data.Binary                        (Binary (..))
 import           Data.ByteString                    (ByteString)
-import qualified Data.ByteString                    as B (concat, empty, length,
+import qualified Data.ByteString                    as B (concat, length,
                                                           null, splitAt)
 import           Data.Maybe                         (fromMaybe)
 import           Data.Word                          (Word16, Word32)
@@ -44,8 +44,9 @@
 discardAll pipe = flush pipe RequestDiscardAll >> void (fetch pipe)
 
 flush :: MonadIO m => Pipe -> Request -> m ()
-flush pipe request = do let chunkSize = fromIntegral (mcs pipe)
-                        let chunks = split chunkSize (pack $ toStructure request)
+flush pipe request = do let bs = pack $ toStructure request
+                        let chunkSize = chunkSizeFor (mcs pipe) bs
+                        let chunks = split chunkSize bs
                         let terminal = encodeStrict (0 :: Word16)
                         let sock = connectionSocket pipe
                         forM_ chunks $ \chunk -> do
@@ -53,18 +54,15 @@
                           send sock $ encodeStrict size
                           send sock chunk
                         send sock terminal
-  where split :: Int -> ByteString -> [ByteString]
-        split size bs | B.null bs = []
-                      | otherwise = let (chunk, rest) = B.splitAt size bs
-                                    in chunk : split size rest
 
 fetch :: MonadIO m => Pipe -> m Response
 fetch pipe = do bs <- B.concat <$> chunks
-                unpack bs >>= fromStructure
+                (unpack $! bs) >>= fromStructure
   where sock = connectionSocket pipe
 
         chunks :: MonadIO m => m [ByteString]
-        chunks = do chunk <- recvWord sock 2 >>= recvChunk sock
+        chunks = do size <- recvWord sock 2
+                    chunk <- recvChunk sock size
                     if B.null chunk then return [] else (chunk:) <$> chunks
 
 -- Helper functions
@@ -86,10 +84,24 @@
 boltVersionProposal bcfg = B.concat $ encodeStrict <$> [version bcfg, 0, 0, 0]
 
 recvWord :: (MonadIO m, Binary a, Integral a) => Socket -> Int -> m a
-recvWord sock size = do bs <- liftIO $ recv sock size
+recvWord sock size = do bs <- recv sock size
                         return (fromMaybe 0 $ decodeStrict <$> bs)
 
 recvChunk :: MonadIO m => Socket -> Word16 -> m ByteString
-recvChunk _    0    = return B.empty
-recvChunk sock size = do let isize = fromIntegral size
-                         fromMaybe B.empty <$> liftIO (recv sock isize)
+recvChunk sock size = B.concat <$> helper (fromIntegral size)
+  where helper :: MonadIO m => Int -> m [ByteString]
+        helper 0  = return []
+        helper sz = do mbChunk <- recv sock sz
+                       case mbChunk of
+                         Just chunk -> (chunk:) <$> helper (sz - B.length chunk)
+                         Nothing    -> fail "Cannot read chunk from sock"
+
+chunkSizeFor :: Word16 -> ByteString -> Int
+chunkSizeFor maxSize bs = 1 + div len noc
+  where len = B.length bs
+        noc = 1 + div len (fromIntegral maxSize)
+
+split :: Int -> ByteString -> [ByteString]
+split size bs | B.null bs = []
+              | otherwise = let (chunk, rest) = B.splitAt size bs
+                            in chunk : split size rest
