diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,3 +1,7 @@
+# Version 1.5.0.1
+Bugfix: `concurrentMerge []` should not block forever, even if this case is
+pathological.
+
 # Version 1.5.0.0
 - Changed the behaviour of `ByteString.splitOn` to not emit empty string if the
   input ends in the delimiter; now `lines` should match Prelude's. Bumped major
diff --git a/io-streams.cabal b/io-streams.cabal
--- a/io-streams.cabal
+++ b/io-streams.cabal
@@ -1,5 +1,5 @@
 Name:                io-streams
-Version:             1.5.0.0
+Version:             1.5.0.1
 License:             BSD3
 License-file:        LICENSE
 Category:            Data, Network, IO-Streams
diff --git a/src/System/IO/Streams/Concurrent.hs b/src/System/IO/Streams/Concurrent.hs
--- a/src/System/IO/Streams/Concurrent.hs
+++ b/src/System/IO/Streams/Concurrent.hs
@@ -23,7 +23,7 @@
 import           Control.Monad              (forM_)
 import           Prelude                    hiding (read)
 ------------------------------------------------------------------------------
-import           System.IO.Streams.Internal (InputStream, OutputStream, makeInputStream, makeOutputStream, read)
+import           System.IO.Streams.Internal (InputStream, OutputStream, makeInputStream, makeOutputStream, nullInput, read)
 
 
 ------------------------------------------------------------------------------
@@ -60,9 +60,14 @@
 -- produced stream does not yield end-of-stream until all of the input streams
 -- have finished.
 --
--- This traps exceptions in each concurrent thread and re-raises them in the
--- current thread.
+-- Any exceptions raised in one of the worker threads will be trapped and
+-- re-raised in the current thread.
+--
+-- If the supplied list is empty, `concurrentMerge` will return an empty
+-- stream. (/Since: 1.5.0.1/)
+--
 concurrentMerge :: [InputStream a] -> IO (InputStream a)
+concurrentMerge [] = nullInput
 concurrentMerge iss = do
     mv    <- newEmptyMVar
     nleft <- newMVar $! length iss
