diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,12 @@
+## 0.5.4.0
+
+* Added cursor interface (`Cursor` and friends)
+
+## 0.5.3.1
+
+* `distinctAggregator`, `joinNullable`, `exists`, `notExists`,
+  `index`, `timestamptzAtTimeZone`
+
 ## 0.5.3.0
 
 * Added support for range types
diff --git a/opaleye.cabal b/opaleye.cabal
--- a/opaleye.cabal
+++ b/opaleye.cabal
@@ -1,6 +1,6 @@
 name:            opaleye
 copyright:       Copyright (c) 2014-2017 Purely Agile Limited
-version:         0.5.3.1
+version:         0.5.4.0
 synopsis:        An SQL-generating DSL targeting PostgreSQL
 description:     An SQL-generating DSL targeting PostgreSQL.  Allows
                  Postgres queries to be written within Haskell in a
@@ -37,7 +37,7 @@
     , case-insensitive    >= 1.2     && < 1.3
     , bytestring          >= 0.10    && < 0.11
     , contravariant       >= 1.2     && < 1.5
-    , postgresql-simple   >= 0.5     && < 0.6
+    , postgresql-simple   >= 0.5.3   && < 0.6
     , pretty              >= 1.1.1.0 && < 1.2
     , product-profunctors >= 0.6.2   && < 0.9
     , profunctors         >= 4.0     && < 5.3
diff --git a/src/Opaleye/Internal/RunQuery.hs b/src/Opaleye/Internal/RunQuery.hs
--- a/src/Opaleye/Internal/RunQuery.hs
+++ b/src/Opaleye/Internal/RunQuery.hs
@@ -4,6 +4,7 @@
 
 import           Control.Applicative (Applicative, pure, (*>), (<*>), liftA2)
 
+import qualified Database.PostgreSQL.Simple.Cursor  as PGSC (Cursor)
 import           Database.PostgreSQL.Simple.Internal (RowParser)
 import           Database.PostgreSQL.Simple.FromField
   (FieldParser, FromField, fromField, pgArrayFieldParser)
@@ -287,3 +288,6 @@
      -- SELECT statement, since we can't select zero
      -- columns.  In that case we have to make sure we
      -- read a single Int.
+
+-- | Cursor within a transaction.
+data Cursor haskells = EmptyCursor | Cursor (RowParser haskells) PGSC.Cursor
diff --git a/src/Opaleye/RunQuery.hs b/src/Opaleye/RunQuery.hs
--- a/src/Opaleye/RunQuery.hs
+++ b/src/Opaleye/RunQuery.hs
@@ -1,15 +1,18 @@
 {-# LANGUAGE FlexibleContexts #-}
 
 module Opaleye.RunQuery (module Opaleye.RunQuery,
-                         QueryRunner,
                          -- * Datatypes
+                         IRQ.Cursor,
+                         QueryRunner,
                          IRQ.QueryRunnerColumn,
                          IRQ.QueryRunnerColumnDefault (..),
                          -- * Creating now 'QueryRunnerColumn's
                          IRQ.fieldQueryRunnerColumn,
                          IRQ.fieldParserQueryRunnerColumn) where
 
+import           Control.Applicative (pure, (<$>))
 import qualified Database.PostgreSQL.Simple as PGS
+import qualified Database.PostgreSQL.Simple.Cursor  as PGSC
 import qualified Database.PostgreSQL.Simple.FromRow as FR
 import qualified Data.String as String
 
@@ -107,6 +110,50 @@
   Nothing   -> return z
   Just sql' -> PGS.foldWith_ parser conn sql' z f
   where (sql, parser) = prepareQuery qr q
+
+-- * Cursor interface
+
+-- | Declare a temporary cursor. The cursor is given a unique name for the given
+-- connection.
+--
+-- Returns 'Nothing' when the query returns zero rows.
+declareCursor
+    :: D.Default QueryRunner columns haskells
+    => PGS.Connection
+    -> Query columns
+    -> IO (IRQ.Cursor haskells)
+declareCursor = declareCursorExplicit D.def
+
+-- | Like 'declareCursor' but takes a 'QueryRunner' explicitly.
+declareCursorExplicit
+    :: QueryRunner columns haskells
+    -> PGS.Connection
+    -> Query columns
+    -> IO (IRQ.Cursor haskells)
+declareCursorExplicit qr conn q =
+    case mbQuery of
+      Nothing    -> pure IRQ.EmptyCursor
+      Just query -> IRQ.Cursor rowParser <$> PGSC.declareCursor conn query
+  where
+    (mbQuery, rowParser) = prepareQuery qr q
+
+-- | Close the given cursor.
+closeCursor :: IRQ.Cursor columns -> IO ()
+closeCursor IRQ.EmptyCursor       = pure ()
+closeCursor (IRQ.Cursor _ cursor) = PGSC.closeCursor cursor
+
+-- | Fold over a chunk of rows, calling the supplied fold-like function on each
+-- row as it is received. In case the cursor is exhausted, a 'Left' value is
+-- returned, otherwise a 'Right' value is returned.
+foldForward
+    :: IRQ.Cursor haskells
+    -> Int
+    -> (a -> haskells -> IO a)
+    -> a
+    -> IO (Either a a)
+foldForward IRQ.EmptyCursor              _chunkSize _f z = pure $ Left z
+foldForward (IRQ.Cursor rowParser cursor) chunkSize  f z =
+    PGSC.foldForwardWithParser cursor rowParser chunkSize f z
 
 -- * Deprecated functions
 
