diff --git a/CHANGELOG.rst b/CHANGELOG.rst
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -6,7 +6,20 @@
 
 .. _PVP: https://pvp.haskell.org/
 
+1.9.0.0 (2020-02-26)
+====================
 
+* Git: :tag:`concurrency-1.9.0.0`
+* Hackage: :hackage:`concurrency-1.9.0.0`
+
+Changed
+~~~~~~~
+
+* (:issue:`286`) Pulled in changes from :hackage:`stm-2.5.0.0` package:
+
+  * Changed ``newTBQueue`` to accept ``Natural`` as a size.
+  * Changed ``lengthTBQueue`` to return a ``Natural``.
+
 1.8.1.0 (2019-11-16)
 ====================
 
@@ -105,6 +118,8 @@
 
     * Make definition of ``readTQueue`` consistent with
       ``readTBQueue``
+
+    * Performance improvements to ``peekTQueue`` and ``peekTBQueue``.
 
 Miscellaneous
 ~~~~~~~~~~~~~
diff --git a/Control/Concurrent/Classy/STM/TBQueue.hs b/Control/Concurrent/Classy/STM/TBQueue.hs
--- a/Control/Concurrent/Classy/STM/TBQueue.hs
+++ b/Control/Concurrent/Classy/STM/TBQueue.hs
@@ -36,23 +36,24 @@
   ) where
 
 import           Control.Monad.STM.Class
+import           Numeric.Natural
 
 -- | 'TBQueue' is an abstract type representing a bounded FIFO
 -- channel.
 --
--- @since 1.0.0.0
+-- @since 1.9.0.0
 data TBQueue stm a
-   = TBQueue (TVar stm Int)
+   = TBQueue (TVar stm Natural)
              (TVar stm [a])
-             (TVar stm Int)
+             (TVar stm Natural)
              (TVar stm [a])
-             {-# UNPACK #-} !Int
+             !Natural
 
--- | Build and returns a new instance of 'TBQueue'
+-- | Builds and returns a new instance of 'TBQueue'
 --
--- @since 1.0.0.0
+-- @since 1.9.0.0
 newTBQueue :: MonadSTM stm
-  => Int   -- ^ maximum number of elements the queue can hold
+  => Natural -- ^ maximum number of elements the queue can hold
   -> stm (TBQueue stm a)
 newTBQueue size = do
   readT  <- newTVar []
@@ -67,11 +68,11 @@
 writeTBQueue :: MonadSTM stm => TBQueue stm a -> a -> stm ()
 writeTBQueue (TBQueue rsize _ wsize writeT _) a = do
   w <- readTVar wsize
-  if w /= 0
+  if w > 0
   then writeTVar wsize $! w - 1
   else do
     r <- readTVar rsize
-    if r /= 0
+    if r > 0
     then do
       writeTVar rsize 0
       writeTVar wsize $! r - 1
@@ -130,10 +131,20 @@
 --
 -- @since 1.0.0.0
 peekTBQueue :: MonadSTM stm => TBQueue stm a -> stm a
-peekTBQueue c = do
-  x <- readTBQueue c
-  unGetTBQueue c x
-  pure x
+peekTBQueue (TBQueue _ readT _ writeT _) = do
+  xs <- readTVar readT
+  case xs of
+    (x:_) -> pure x
+    [] -> do
+      ys <- readTVar writeT
+      case ys of
+        [] -> retry
+        _  -> do
+          let (z:zs) = reverse ys -- NB. lazy: we want the transaction to be
+                                  -- short, otherwise it will conflict
+          writeTVar writeT []
+          writeTVar readT (z:zs)
+          pure z
 
 -- | A version of 'peekTBQueue' which does not retry. Instead it
 -- returns @Nothing@ if no value is available.
@@ -167,8 +178,8 @@
 
 -- |Return the length of a 'TBQueue'.
 --
--- @since 1.6.1.0
-lengthTBQueue :: MonadSTM stm => TBQueue stm a -> stm Int
+-- @since 1.9.0.0
+lengthTBQueue :: MonadSTM stm => TBQueue stm a -> stm Natural
 lengthTBQueue (TBQueue rsize _ wsize _ size) = do
   r <- readTVar rsize
   w <- readTVar wsize
diff --git a/Control/Concurrent/Classy/STM/TMVar.hs b/Control/Concurrent/Classy/STM/TMVar.hs
--- a/Control/Concurrent/Classy/STM/TMVar.hs
+++ b/Control/Concurrent/Classy/STM/TMVar.hs
@@ -29,7 +29,7 @@
   , swapTMVar
   ) where
 
-import           Control.Monad           (liftM, unless, when)
+import           Control.Monad           (unless, when)
 import           Control.Monad.STM.Class
 import           Data.Maybe              (isJust, isNothing)
 
@@ -131,7 +131,7 @@
 --
 -- @since 1.0.0.0
 isEmptyTMVar :: MonadSTM stm => TMVar stm a -> stm Bool
-isEmptyTMVar ctmvar = isNothing `liftM` tryReadTMVar ctmvar
+isEmptyTMVar ctmvar = isNothing <$> tryReadTMVar ctmvar
 
 -- | Swap the contents of a 'TMVar' returning the old contents, or
 -- 'retry' if it is empty.
diff --git a/Control/Concurrent/Classy/STM/TQueue.hs b/Control/Concurrent/Classy/STM/TQueue.hs
--- a/Control/Concurrent/Classy/STM/TQueue.hs
+++ b/Control/Concurrent/Classy/STM/TQueue.hs
@@ -108,10 +108,20 @@
 --
 -- @since 1.0.0.0
 peekTQueue :: MonadSTM stm => TQueue stm a -> stm a
-peekTQueue c = do
-  x <- readTQueue c
-  unGetTQueue c x
-  pure x
+peekTQueue (TQueue readT writeT) = do
+  xs <- readTVar readT
+  case xs of
+    (x:_) -> pure x
+    [] -> do
+      ys <- readTVar writeT
+      case ys of
+        [] -> retry
+        _  -> do
+          let (z:zs) = reverse ys -- NB. lazy: we want the transaction to be
+                                  -- short, otherwise it will conflict
+          writeTVar writeT []
+          writeTVar readT (z:zs)
+          pure z
 
 -- | A version of 'peekTQueue' which does not retry. Instead it
 -- returns @Nothing@ if no value is available.
diff --git a/Control/Monad/STM/Class.hs b/Control/Monad/STM/Class.hs
--- a/Control/Monad/STM/Class.hs
+++ b/Control/Monad/STM/Class.hs
@@ -43,9 +43,7 @@
 -- here.
 --
 -- __Deviations:__ An instance of @MonadSTM@ is not required to be a
--- @MonadFix@, unlike @STM@. The @always@ and @alwaysSucceeds@
--- functions are not provided; if you need these file an issue and
--- I'll look into it.
+-- @MonadFix@, unlike @STM@.
 module Control.Monad.STM.Class
   ( MonadSTM(..)
   , retry
diff --git a/concurrency.cabal b/concurrency.cabal
--- a/concurrency.cabal
+++ b/concurrency.cabal
@@ -2,7 +2,7 @@
 -- documentation, see http://haskell.org/cabal/users-guide/
 
 name:                concurrency
-version:             1.8.1.0
+version:             1.9.0.0
 synopsis:            Typeclasses, functions, and data types for concurrency and STM.
 
 description:
@@ -32,7 +32,7 @@
 source-repository this
   type:     git
   location: https://github.com/barrucadu/dejafu.git
-  tag:      concurrency-1.8.1.0
+  tag:      concurrency-1.9.0.0
 
 library
   exposed-modules:     Control.Monad.Conc.Class
