diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
 # Unreleased
 
+# 0.3.0.0
+
+* Add `unsafeLiftSql` ([#38](https://github.com/brandonchinn178/persistent-mtl/pull/38))
+
 # 0.2.2.0
 
 * Fix for persistent 2.13
diff --git a/persistent-mtl.cabal b/persistent-mtl.cabal
--- a/persistent-mtl.cabal
+++ b/persistent-mtl.cabal
@@ -5,7 +5,7 @@
 -- see: https://github.com/sol/hpack
 
 name:           persistent-mtl
-version:        0.2.2.0
+version:        0.3.0.0
 synopsis:       Monad transformer for the persistent API
 description:    A monad transformer and mtl-style type class for using the
                 persistent API directly in your monad transformer stack.
@@ -69,6 +69,7 @@
       MockSqlQueryT
       SqlQueryRepTest
       TestUtils.DB
+      TestUtils.Esqueleto
       TestUtils.Match
       Paths_persistent_mtl
   hs-source-dirs:
@@ -79,6 +80,7 @@
     , bytestring
     , conduit
     , containers
+    , esqueleto
     , monad-logger
     , persistent
     , persistent-mtl
diff --git a/src/Database/Persist/Monad/Shim.hs b/src/Database/Persist/Monad/Shim.hs
--- a/src/Database/Persist/Monad/Shim.hs
+++ b/src/Database/Persist/Monad/Shim.hs
@@ -13,6 +13,7 @@
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE GADTs #-}
 {-# LANGUAGE PatternSynonyms #-}
+{-# LANGUAGE RankNTypes #-}
 
 module Database.Persist.Monad.Shim where
 
@@ -515,6 +516,22 @@
   => IsolationLevel -> m ()
 transactionUndoWithIsolation a1 = runQueryRep $ TransactionUndoWithIsolation a1
 #endif
+
+-- | Lift an arbitrary 'SqlPersistT' action into 'MonadSqlQuery'.
+--
+-- This is unsafe because the action may be rerun. This function should
+-- primarily be used to interop with other libraries built on top of
+-- persistent.
+--
+-- Example usage:
+--
+-- @
+-- -- | Run an esqueleto select.
+-- select :: (MonadSqlQuery m, E.SqlSelect a r) => E.SqlQuery a -> m [r]
+-- select q = unsafeLiftSql "esqueleto-select" (E.select q)
+-- @
+unsafeLiftSql :: MonadSqlQuery m => Text -> (forall m2. MonadIO m2 => SqlPersistT m2 a) -> m a
+unsafeLiftSql label action = runQueryRep $ UnsafeLiftSql label action
 
 {- Helpers -}
 
diff --git a/src/Database/Persist/Monad/SqlQueryRep.hs b/src/Database/Persist/Monad/SqlQueryRep.hs
--- a/src/Database/Persist/Monad/SqlQueryRep.hs
+++ b/src/Database/Persist/Monad/SqlQueryRep.hs
@@ -15,6 +15,7 @@
 {-# LANGUAGE GADTs #-}
 {-# LANGUAGE LambdaCase #-}
 {-# LANGUAGE PatternSynonyms #-}
+{-# LANGUAGE RankNTypes #-}
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE TypeApplications #-}
 
@@ -31,6 +32,7 @@
 import Data.Map (Map)
 import Data.Proxy (Proxy(..))
 import Data.Text (Text)
+import qualified Data.Text as Text
 import Data.Typeable (Typeable, eqT, typeRep, (:~:)(..))
 import Data.Void (Void)
 import Database.Persist.Sql as Persist hiding (pattern Update)
@@ -440,6 +442,10 @@
     => IsolationLevel -> SqlQueryRep Void ()
 #endif
 
+  -- | Constructor for lifting an arbitrary SqlPersistT action into SqlQueryRep.
+  UnsafeLiftSql
+    :: Text -> (forall m. MonadIO m => Persist.SqlPersistT m a) -> SqlQueryRep Void a
+
 instance Typeable record => Show (SqlQueryRep record a) where
   show = \case
     Get{} -> "Get{..}" ++ record
@@ -546,6 +552,7 @@
 #if MIN_VERSION_persistent(2,9,0)
     TransactionUndoWithIsolation{} -> "TransactionUndoWithIsolation{..}" ++ record
 #endif
+    UnsafeLiftSql label _ -> "UnsafeLiftSql{" ++ Text.unpack label ++ "}"
     where
       record = case recordTypeRep of
         Just recordType -> "<" ++ show recordType ++ ">"
@@ -662,3 +669,4 @@
 #if MIN_VERSION_persistent(2,9,0)
   TransactionUndoWithIsolation a1 -> Persist.transactionUndoWithIsolation a1
 #endif
+  UnsafeLiftSql _ action -> action
diff --git a/test/Integration.hs b/test/Integration.hs
--- a/test/Integration.hs
+++ b/test/Integration.hs
@@ -15,6 +15,11 @@
 import Data.Text (Text)
 import qualified Data.Text as Text
 import Data.Typeable (Typeable)
+#if MIN_VERSION_esqueleto(3,5,0)
+import qualified Database.Esqueleto.Experimental as E
+#else
+import qualified Database.Esqueleto as E
+#endif
 import Database.Persist.Sql
     ( Entity(..)
     , Migration
@@ -48,6 +53,7 @@
 import Database.Persist.Monad
 import Example
 import TestUtils.DB (BackendType(..), allBackendTypes)
+import TestUtils.Esqueleto (esqueletoSelect)
 import TestUtils.Match (Match(..), (@?~))
 
 tests :: TestTree
@@ -59,6 +65,7 @@
   [ testWithTransaction backendType
   , testComposability backendType
   , testPersistentAPI backendType
+  , testInterop backendType
   ]
 
 testWithTransaction :: BackendType -> TestTree
@@ -820,6 +827,21 @@
         getPeopleNames
       result @?= []
 #endif
+  ]
+
+testInterop :: BackendType -> TestTree
+testInterop backendType = testGroup "Interop with third-party Persistent libraries"
+  [ testCase "unsafeLiftSql" $ do
+      let alice = person "Alice"
+      result <- runTestApp backendType $ do
+        insert_ alice
+        esqueletoSelect $
+#if MIN_VERSION_esqueleto(3,5,0)
+          E.from $ E.table @Person
+#else
+          E.from $ \p -> return p
+#endif
+      result @?= [Entity 1 alice]
   ]
 
 {- Persistent helpers -}
diff --git a/test/TestUtils/Esqueleto.hs b/test/TestUtils/Esqueleto.hs
new file mode 100644
--- /dev/null
+++ b/test/TestUtils/Esqueleto.hs
@@ -0,0 +1,19 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE OverloadedStrings #-}
+
+module TestUtils.Esqueleto
+  ( esqueletoSelect
+  ) where
+
+#if MIN_VERSION_esqueleto(3,5,0)
+import qualified Database.Esqueleto.Experimental as E
+import qualified Database.Esqueleto.Internal.Internal as E
+#else
+import qualified Database.Esqueleto as E
+import qualified Database.Esqueleto.Internal.Sql as E
+#endif
+
+import Database.Persist.Monad (MonadSqlQuery, unsafeLiftSql)
+
+esqueletoSelect :: (MonadSqlQuery m, E.SqlSelect a r) => E.SqlQuery a -> m [r]
+esqueletoSelect q = unsafeLiftSql "esqueleto-select" (E.select q)
