diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,17 +1,26 @@
 # Changelog for persistent
 
-## 2.11.0.4
-
-* Fix a compile error [#1213](https://github.com/yesodweb/persistent/pull/1213)
-    * That's what I get for running this stuff with flakey CI!
-
-## 2.11.0.3
+## 2.12 (unreleased)
 
-* Backported the fix from [#1207](https://github.com/yesodweb/persistent/pull/1207) for asynchronous exceptions.
-    * Deprecated the `Acquire` family of functions.
+* [#1162](https://github.com/yesodweb/persistent/pull/1162)
+  * Replace `askLogFunc` with `askLoggerIO`
+* Decomposed `HaskellName` into `ConstraintNameHS`, `EntityNameHS`, `FieldNameHS`. Decomposed `DBName` into `ConstraintNameDB`, `EntityNameDB`, `FieldNameDB` respectively. [#1174](https://github.com/yesodweb/persistent/pull/1174)
+* Use `resourcet-pool` to break out some `Data.Pool` logic [#1163](https://github.com/yesodweb/persistent/pull/1163)
+* [#1178](https://github.com/yesodweb/persistent/pull/1178)
+  * Added 'withBaseBackend', 'withCompatible' to ease use of base/compatible backend queries in external code.
+* Added GHC 8.2.2 and GHC 8.4.4 back into the CI and `persistent` builds on 8.2.2 again [#1181](https://github.com/yesodweb/persistent/issues/1181)
+* [#1179](https://github.com/yesodweb/persistent/pull/1179)
+  * Added `Compatible`, a newtype for marking a backend as compatible with another. Use it with `DerivingVia` to derive simple instances based on backend compatibility.
+  * Added `makeCompatibleInstances` and `makeCompatibleKeyInstances`, TemplateHaskell invocations for auto-generating standalone derivations using `Compatible` and `DerivingVia`.
+* [#1207](https://github.com/yesodweb/persistent/pull/1207)
+    * @codygman discovered a bug in [issue #1199](https://github.com/yesodweb/persistent/issues/1199) where postgres connections were being returned to the `Pool SqlBackend` in an inconsistent state.
+      @parsonsmatt debugged the issue and determined that it had something to do with asynchronous exceptions. 
+      Declaring it to be "out of his pay grade," he ripped the `poolToAcquire` function out and replaced it with `Data.Pool.withResource`, which doesn't exhibit the bug.
+      Fortunately, this doesn't affect the public API, and can be a mere bug release.
+    * Removed the functions `unsafeAcquireSqlConnFromPool`, `acquireASqlConnFromPool`, and `acquireSqlConnFromPoolWithIsolation`. 
+      For a replacement, see `runSqlPoolNoTransaction` and `runSqlPoolWithHooks`.
 
 ## 2.11.0.2
-
 * Fix a bug where an empty entity definition would break parsing of `EntityDef`s. [#1176](https://github.com/yesodweb/persistent/issues/1176)
 
 ## 2.11.0.1
@@ -71,7 +80,7 @@
 * [#1142](https://github.com/yesodweb/persistent/pull/1142)
     * Deprecate `hasCompositeKey` in favor of `hasCustomPrimaryKey` and `hasCompositePrimaryKey` functions.
 * [#1098](https://github.com/yesodweb/persistent/pull/1098)
-  * Add support for configuring the number of stripes and idle timeout for connection pools 
+  * Add support for configuring the number of stripes and idle timeout for connection pools
     * For functions that do not specify an idle timeout, the default has been bumped to 600 seconds.
       * This change is based off the experience of two production codebases. See [#775](https://github.com/yesodweb/persistent/issues/775)
     * Add a new type `ConnectionPoolConfig` to configure the number of connections in a pool, their idle timeout, and stripe size.
@@ -105,7 +114,7 @@
 ## 2.10.5.1
 
 * [#1024](https://github.com/yesodweb/persistent/pull/1024)
-    * Add the ability to do documentation comments in entity definition syntax. Unfortunately, TemplateHaskell cannot add documentation comments, so this can't be used to add Haddocks to entities. 
+    * Add the ability to do documentation comments in entity definition syntax. Unfortunately, TemplateHaskell cannot add documentation comments, so this can't be used to add Haddocks to entities.
     * Add Haddock explainers for some of the supported entity syntax in `Database.Persist.Quasi`
 
 ## 2.10.5
diff --git a/Database/Persist/Class.hs b/Database/Persist/Class.hs
--- a/Database/Persist/Class.hs
+++ b/Database/Persist/Class.hs
@@ -126,9 +126,11 @@
 
     -- * Lifting
     , HasPersistBackend (..)
+    , withBaseBackend
     , IsPersistBackend ()
     , liftPersist
     , BackendCompatible (..)
+    , withCompatibleBackend
 
     -- * JSON utilities
     , keyValueEntityToJSON, keyValueEntityFromJSON
diff --git a/Database/Persist/Class/PersistEntity.hs b/Database/Persist/Class/PersistEntity.hs
--- a/Database/Persist/Class/PersistEntity.hs
+++ b/Database/Persist/Class/PersistEntity.hs
@@ -104,7 +104,7 @@
     -- | A meta operation to retrieve all the 'Unique' keys.
     persistUniqueKeys :: record -> [Unique record]
     -- | A lower level operation.
-    persistUniqueToFieldNames :: Unique record -> [(HaskellName, DBName)]
+    persistUniqueToFieldNames :: Unique record -> [(FieldNameHS, FieldNameDB)]
     -- | A lower level operation.
     persistUniqueToValues :: Unique record -> [PersistValue]
 
@@ -128,7 +128,7 @@
 recordName
     :: (PersistEntity record)
     => record -> Text
-recordName = unHaskellName . entityHaskell . entityDef . Just
+recordName = unEntityNameHS . entityHaskell . entityDef . Just
 
 -- | Updating a database entity.
 --
diff --git a/Database/Persist/Class/PersistStore.hs b/Database/Persist/Class/PersistStore.hs
--- a/Database/Persist/Class/PersistStore.hs
+++ b/Database/Persist/Class/PersistStore.hs
@@ -2,6 +2,7 @@
 {-# LANGUAGE ExplicitForAll #-}
 module Database.Persist.Class.PersistStore
     ( HasPersistBackend (..)
+    , withBaseBackend
     , IsPersistBackend (..)
     , PersistRecordBackend
     , liftPersist
@@ -17,12 +18,13 @@
     , insertRecord
     , ToBackendKey(..)
     , BackendCompatible(..)
+    , withCompatibleBackend
     ) where
 
 import Control.Exception (throwIO)
 import Control.Monad.IO.Class (MonadIO, liftIO)
 import Control.Monad.Reader (MonadReader (ask), runReaderT)
-import Control.Monad.Trans.Reader (ReaderT)
+import Control.Monad.Trans.Reader (ReaderT, withReaderT)
 import qualified Data.Aeson as A
 import Data.Map (Map)
 import qualified Data.Map as Map
@@ -43,6 +45,16 @@
 class HasPersistBackend backend where
     type BaseBackend backend
     persistBackend :: backend -> BaseBackend backend
+
+-- | Run a query against a larger backend by plucking out @BaseBackend backend@
+--
+-- This is a helper for reusing existing queries when expanding the backend type.
+--
+-- @since 2.12.0
+withBaseBackend :: (HasPersistBackend backend)
+                => ReaderT (BaseBackend backend) m a -> ReaderT backend m a
+withBaseBackend = withReaderT persistBackend
+
 -- | Class which witnesses that @backend@ is essentially the same as @BaseBackend backend@.
 -- That is, they're isomorphic and @backend@ is just some wrapper over @BaseBackend backend@.
 class (HasPersistBackend backend) => IsPersistBackend backend where
@@ -51,6 +63,10 @@
     -- to accidentally run a write query against a read-only database.
     mkPersistBackend :: BaseBackend backend -> backend
 
+-- NB: there is a deliberate *lack* of an equivalent to 'withBaseBackend' for
+-- 'IsPersistentBackend'. We don't want it to be easy for the user to construct
+-- a backend when they're not meant to.
+
 -- | This class witnesses that two backend are compatible, and that you can
 -- convert from the @sub@ backend into the @sup@ backend. This is similar
 -- to the 'HasPersistBackend' and 'IsPersistBackend' classes, but where you
@@ -88,12 +104,22 @@
 --
 -- -- after:
 -- asdf' :: 'BackendCompatible' SqlBackend backend => ReaderT backend m ()
--- asdf' = withReaderT 'projectBackend' asdf
+-- asdf' = 'withCompatibleBackend' asdf
 -- @
 --
 -- @since 2.7.1
 class BackendCompatible sup sub where
     projectBackend :: sub -> sup
+
+-- | Run a query against a compatible backend, by projecting the backend
+--
+-- This is a helper for using queries which run against a specific backend type
+-- that your backend is compatible with.
+--
+-- @since 2.12.0
+withCompatibleBackend :: (BackendCompatible sup sub)
+                      => ReaderT sup m a -> ReaderT sub m a
+withCompatibleBackend = withReaderT projectBackend
 
 -- | A convenient alias for common type signatures
 type PersistRecordBackend record backend = (PersistEntity record, PersistEntityBackend record ~ BaseBackend backend)
diff --git a/Database/Persist/Compatible.hs b/Database/Persist/Compatible.hs
new file mode 100644
--- /dev/null
+++ b/Database/Persist/Compatible.hs
@@ -0,0 +1,9 @@
+module Database.Persist.Compatible
+    ( Compatible(..)
+    , makeCompatibleInstances
+    , makeCompatibleKeyInstances
+    ) where
+
+import Database.Persist.Compatible.Types
+import Database.Persist.Compatible.TH
+
diff --git a/Database/Persist/Compatible/TH.hs b/Database/Persist/Compatible/TH.hs
new file mode 100644
--- /dev/null
+++ b/Database/Persist/Compatible/TH.hs
@@ -0,0 +1,107 @@
+{-# LANGUAGE DerivingVia #-}
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE StandaloneDeriving #-}
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE TupleSections #-}
+
+module Database.Persist.Compatible.TH
+    ( makeCompatibleInstances
+    , makeCompatibleKeyInstances
+    ) where
+
+import Data.Aeson
+import Database.Persist.Class
+import Database.Persist.Sql.Class
+import Language.Haskell.TH
+
+import Database.Persist.Compatible.Types
+
+-- | Gives a bunch of useful instance declarations for a backend based on its
+-- compatibility with another backend, using 'Compatible'.
+--
+-- The argument should be a type of the form @ forall v1 ... vn. Compatible b s @
+-- (Quantification is optional, but supported because TH won't let you have
+-- unbound type variables in a type splice). The instance is produced for @s@
+-- based on the instance defined for @b@, which is constrained in the instance
+-- head to exist.
+--
+-- @v1 ... vn@ are implicitly quantified in the instance, which is derived via
+-- @'Compatible' b s@.
+--
+-- @since 2.12
+makeCompatibleInstances :: Q Type -> Q [Dec]
+makeCompatibleInstances compatibleType = do
+        (b, s) <- compatibleType >>= \case
+            ForallT _ _ (AppT (AppT (ConT conTName) b) s) ->
+                if conTName == ''Compatible
+                    then pure (b, s)
+                    else fail $
+                                "Cannot make `deriving via` instances if the argument is " <>
+                                "not of the form `forall v1 ... vn. Compatible sub sup`"
+            AppT (AppT (ConT conTName) b) s ->
+                if conTName == ''Compatible
+                    then pure (b, s)
+                    else fail $
+                                "Cannot make `deriving via` instances if the argument is " <>
+                                "not of the form `Compatible sub sup`"
+            _ -> fail $
+                        "Cannot make `deriving via` instances if the argument is " <>
+                        "not of the form `Compatible sub sup`"
+
+        [d|
+                deriving via (Compatible $(return b) $(return s)) instance (HasPersistBackend $(return b)) => HasPersistBackend $(return s)
+                deriving via (Compatible $(return b) $(return s)) instance (HasPersistBackend $(return b), PersistStoreRead $(return b)) => PersistStoreRead $(return s)
+                deriving via (Compatible $(return b) $(return s)) instance (HasPersistBackend $(return b), PersistQueryRead $(return b)) => PersistQueryRead $(return s)
+                deriving via (Compatible $(return b) $(return s)) instance (HasPersistBackend $(return b), PersistUniqueRead $(return b)) => PersistUniqueRead $(return s)
+                deriving via (Compatible $(return b) $(return s)) instance (HasPersistBackend $(return b), PersistStoreWrite $(return b)) => PersistStoreWrite $(return s)
+                deriving via (Compatible $(return b) $(return s)) instance (HasPersistBackend $(return b), PersistQueryWrite $(return b)) => PersistQueryWrite $(return s)
+                deriving via (Compatible $(return b) $(return s)) instance (HasPersistBackend $(return b), PersistUniqueWrite $(return b)) => PersistUniqueWrite $(return s)
+            |]
+
+-- | Gives a bunch of useful instance declarations for a backend key based on
+-- its compatibility with another backend & key, using 'Compatible'.
+--
+-- The argument should be a type of the form @ forall v1 ... vn. Compatible b s @
+-- (Quantification is optional, but supported because TH won't let you have
+-- unbound type variables in a type splice). The instance is produced for
+-- @'BackendKey' s@ based on the instance defined for @'BackendKey' b@, which
+-- is constrained in the instance head to exist.
+--
+-- @v1 ... vn@ are implicitly quantified in the instance, which is derived via
+-- @'BackendKey' ('Compatible' b s)@.
+--
+-- @since 2.12
+makeCompatibleKeyInstances :: Q Type -> Q [Dec]
+makeCompatibleKeyInstances compatibleType = do
+    (b, s) <- compatibleType >>= \case
+        ForallT _ _ (AppT (AppT (ConT conTName) b) s) ->
+            if conTName == ''Compatible
+                then pure (b, s)
+                else fail $
+                            "Cannot make `deriving via` instances if the argument is " <>
+                            "not of the form `forall v1 ... vn. Compatible sub sup`"
+        AppT (AppT (ConT conTName) b) s ->
+            if conTName == ''Compatible
+                then pure (b, s)
+                else fail $
+                            "Cannot make `deriving via` instances if the argument is " <>
+                            "not of the form `Compatible sub sup`"
+        _ -> fail $
+                    "Cannot make `deriving via` instances if the argument is " <>
+                    "not of the form `Compatible sub sup`"
+
+    [d|
+            deriving via (BackendKey (Compatible $(return b) $(return s))) instance (PersistCore $(return b), PersistCore $(return s), Show (BackendKey $(return b))) => Show (BackendKey $(return s))
+            deriving via (BackendKey (Compatible $(return b) $(return s))) instance (PersistCore $(return b), PersistCore $(return s), Read (BackendKey $(return b))) => Read (BackendKey $(return s))
+            deriving via (BackendKey (Compatible $(return b) $(return s))) instance (PersistCore $(return b), PersistCore $(return s), Eq (BackendKey $(return b))) => Eq (BackendKey $(return s))
+            deriving via (BackendKey (Compatible $(return b) $(return s))) instance (PersistCore $(return b), PersistCore $(return s), Ord (BackendKey $(return b))) => Ord (BackendKey $(return s))
+            deriving via (BackendKey (Compatible $(return b) $(return s))) instance (PersistCore $(return b), PersistCore $(return s), Num (BackendKey $(return b))) => Num (BackendKey $(return s))
+            deriving via (BackendKey (Compatible $(return b) $(return s))) instance (PersistCore $(return b), PersistCore $(return s), Integral (BackendKey $(return b))) => Integral (BackendKey $(return s))
+            deriving via (BackendKey (Compatible $(return b) $(return s))) instance (PersistCore $(return b), PersistCore $(return s), PersistField (BackendKey $(return b))) => PersistField (BackendKey $(return s))
+            deriving via (BackendKey (Compatible $(return b) $(return s))) instance (PersistCore $(return b), PersistCore $(return s), PersistFieldSql (BackendKey $(return b))) => PersistFieldSql (BackendKey $(return s))
+            deriving via (BackendKey (Compatible $(return b) $(return s))) instance (PersistCore $(return b), PersistCore $(return s), Real (BackendKey $(return b))) => Real (BackendKey $(return s))
+            deriving via (BackendKey (Compatible $(return b) $(return s))) instance (PersistCore $(return b), PersistCore $(return s), Enum (BackendKey $(return b))) => Enum (BackendKey $(return s))
+            deriving via (BackendKey (Compatible $(return b) $(return s))) instance (PersistCore $(return b), PersistCore $(return s), Bounded (BackendKey $(return b))) => Bounded (BackendKey $(return s))
+            deriving via (BackendKey (Compatible $(return b) $(return s))) instance (PersistCore $(return b), PersistCore $(return s), ToJSON (BackendKey $(return b))) => ToJSON (BackendKey $(return s))
+            deriving via (BackendKey (Compatible $(return b) $(return s))) instance (PersistCore $(return b), PersistCore $(return s), FromJSON (BackendKey $(return b))) => FromJSON (BackendKey $(return s))
+        |]
diff --git a/Database/Persist/Compatible/Types.hs b/Database/Persist/Compatible/Types.hs
new file mode 100644
--- /dev/null
+++ b/Database/Persist/Compatible/Types.hs
@@ -0,0 +1,141 @@
+{-# OPTIONS_GHC -Wno-unused-top-binds #-}
+{- You can't export a data family constructor, so there's an "unused" warning -}
+{-# LANGUAGE DerivingVia #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE StandaloneDeriving #-}
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE TypeApplications #-}
+{-# LANGUAGE UndecidableInstances #-}
+
+module Database.Persist.Compatible.Types
+    ( Compatible(..)
+    ) where
+
+import Data.Aeson
+import Database.Persist.Class
+import Database.Persist.Sql.Class
+import Control.Monad.Trans.Reader (withReaderT)
+
+
+-- | A newtype wrapper for compatible backends, mainly useful for @DerivingVia@.
+--
+-- When writing a new backend that is 'BackendCompatible' with an existing backend,
+-- instances for the new backend can be naturally defined in terms of the
+-- instances for the existing backend.
+--
+-- For example, if you decide to augment the 'SqlBackend' with some additional
+-- features:
+--
+-- @
+-- data BetterSqlBackend = BetterSqlBackend { sqlBackend :: SqlBackend, ... }
+--
+-- instance BackendCompatible SqlBackend BetterSqlBackend where
+--   projectBackend = sqlBackend
+-- @
+--
+-- Then you can use @DerivingVia@ to automatically get instances like:
+--
+-- @
+-- deriving via (Compatible SqlBackend BetterSqlBackend) instance PersistStoreRead BetterSqlBackend
+-- deriving via (Compatible SqlBackend BetterSqlBackend) instance PersistStoreWrite BetterSqlBackend
+-- ...
+-- @
+--
+-- These instances will go through the compatible backend (in this case, 'SqlBackend')
+-- for all their queries.
+--
+-- These instances require that both backends have the same 'BaseBackend', but
+-- deriving 'HasPersistBackend' will enforce that for you.
+--
+-- @
+-- deriving via (Compatible SqlBackend BetterSqlBackend) instance HasPersistBackend BetterSqlBackend
+-- @
+--
+-- @since 2.12
+newtype Compatible b s = Compatible { unCompatible :: s }
+
+instance (BackendCompatible b s, HasPersistBackend b) => HasPersistBackend (Compatible b s) where
+    type BaseBackend (Compatible b s) = BaseBackend b
+    persistBackend = persistBackend . projectBackend @b @s . unCompatible
+
+instance (BackendCompatible b s, PersistCore b) => PersistCore (Compatible b s) where
+    -- | A newtype wrapper around @'BackendKey' b@, mainly useful for @DerivingVia@.
+    --
+    -- Similarly to @'Compatible' b s@, this data family instance is handy for deriving
+    -- instances for @'BackendKey' s@ by defining them in terms of @'BackendKey' b@.
+    --
+    --
+    -- For example, if you decide to augment the 'SqlBackend' with some additional
+    -- features:
+    --
+    -- @
+    -- data BetterSqlBackend = BetterSqlBackend { sqlBackend :: SqlBackend, ... }
+    --
+    -- instance PersistCore BetterSqlBackend where
+    --   newtype BackendKey BetterSqlBackend = BSQLKey { unBSQLKey :: BackendKey (Compatible SqlBackend BetterSqlBackend) }
+    -- @
+    --
+    -- Then you can use @DerivingVia@ to automatically get instances like:
+    --
+    -- @
+    -- deriving via BackendKey (Compatible SqlBackend BetterSqlBackend) instance Show (BackendKey BetterSqlBackend)
+    -- ...
+    -- @
+    --
+    -- These instances will go through the compatible backend's key (in this case,
+    -- @'BackendKey' 'SqlBackend'@) for all their logic.
+    newtype BackendKey (Compatible b s) = CompatibleKey { unCompatibleKey :: BackendKey b }
+
+instance (HasPersistBackend b, BackendCompatible b s, PersistStoreRead b) => PersistStoreRead (Compatible b s) where
+    get = withReaderT (projectBackend @b @s . unCompatible) . get
+    getMany = withReaderT (projectBackend @b @s . unCompatible) . getMany
+
+instance (HasPersistBackend b, BackendCompatible b s, PersistQueryRead b) => PersistQueryRead (Compatible b s) where
+    selectSourceRes filts opts = withReaderT (projectBackend @b @s . unCompatible) $ selectSourceRes filts opts
+    selectFirst filts opts = withReaderT (projectBackend @b @s . unCompatible) $ selectFirst filts opts
+    selectKeysRes filts opts = withReaderT (projectBackend @b @s . unCompatible) $ selectKeysRes filts opts
+    count = withReaderT (projectBackend @b @s . unCompatible) . count
+    exists = withReaderT (projectBackend @b @s . unCompatible) . exists
+
+instance (HasPersistBackend b, BackendCompatible b s, PersistQueryWrite b) => PersistQueryWrite (Compatible b s) where
+    updateWhere filts updates = withReaderT (projectBackend @b @s . unCompatible) $ updateWhere filts updates
+    deleteWhere = withReaderT (projectBackend @b @s . unCompatible) . deleteWhere
+
+instance (HasPersistBackend b, BackendCompatible b s, PersistUniqueRead b) => PersistUniqueRead (Compatible b s) where
+    getBy = withReaderT (projectBackend @b @s . unCompatible) . getBy
+
+instance (HasPersistBackend b, BackendCompatible b s, PersistStoreWrite b) => PersistStoreWrite (Compatible b s) where
+    insert = withReaderT (projectBackend @b @s . unCompatible) . insert
+    insert_ = withReaderT (projectBackend @b @s . unCompatible) . insert_
+    insertMany = withReaderT (projectBackend @b @s . unCompatible) . insertMany
+    insertMany_ = withReaderT (projectBackend @b @s . unCompatible) . insertMany_
+    insertEntityMany = withReaderT (projectBackend @b @s . unCompatible) . insertEntityMany
+    insertKey k = withReaderT (projectBackend @b @s . unCompatible) . insertKey k
+    repsert k = withReaderT (projectBackend @b @s . unCompatible) . repsert k
+    repsertMany = withReaderT (projectBackend @b @s . unCompatible) . repsertMany
+    replace k = withReaderT (projectBackend @b @s . unCompatible) . replace k
+    delete = withReaderT (projectBackend @b @s . unCompatible) . delete
+    update k = withReaderT (projectBackend @b @s . unCompatible) . update k
+    updateGet k = withReaderT (projectBackend @b @s . unCompatible) . updateGet k
+
+instance (HasPersistBackend b, BackendCompatible b s, PersistUniqueWrite b) => PersistUniqueWrite (Compatible b s) where
+    deleteBy = withReaderT (projectBackend @b @s . unCompatible) . deleteBy
+    insertUnique = withReaderT (projectBackend @b @s . unCompatible) . insertUnique
+    upsert rec = withReaderT (projectBackend @b @s . unCompatible) . upsert rec
+    upsertBy uniq rec = withReaderT (projectBackend @b @s . unCompatible) . upsertBy uniq rec
+    putMany = withReaderT (projectBackend @b @s . unCompatible) . putMany
+
+deriving via (BackendKey b) instance (BackendCompatible b s, Show (BackendKey b)) => Show (BackendKey (Compatible b s))
+deriving via (BackendKey b) instance (BackendCompatible b s, Read (BackendKey b)) => Read (BackendKey (Compatible b s))
+deriving via (BackendKey b) instance (BackendCompatible b s, Eq (BackendKey b)) => Eq (BackendKey (Compatible b s))
+deriving via (BackendKey b) instance (BackendCompatible b s, Ord (BackendKey b)) => Ord (BackendKey (Compatible b s))
+deriving via (BackendKey b) instance (BackendCompatible b s, Num (BackendKey b)) => Num (BackendKey (Compatible b s))
+deriving via (BackendKey b) instance (BackendCompatible b s, Integral (BackendKey b)) => Integral (BackendKey (Compatible b s))
+deriving via (BackendKey b) instance (BackendCompatible b s, PersistField (BackendKey b)) => PersistField (BackendKey (Compatible b s))
+deriving via (BackendKey b) instance (BackendCompatible b s, PersistFieldSql (BackendKey b)) => PersistFieldSql (BackendKey (Compatible b s))
+deriving via (BackendKey b) instance (BackendCompatible b s, Real (BackendKey b)) => Real (BackendKey (Compatible b s))
+deriving via (BackendKey b) instance (BackendCompatible b s, Enum (BackendKey b)) => Enum (BackendKey (Compatible b s))
+deriving via (BackendKey b) instance (BackendCompatible b s, Bounded (BackendKey b)) => Bounded (BackendKey (Compatible b s))
+deriving via (BackendKey b) instance (BackendCompatible b s, ToJSON (BackendKey b)) => ToJSON (BackendKey (Compatible b s))
+deriving via (BackendKey b) instance (BackendCompatible b s, FromJSON (BackendKey b)) => FromJSON (BackendKey (Compatible b s))
diff --git a/Database/Persist/Quasi.hs b/Database/Persist/Quasi.hs
--- a/Database/Persist/Quasi.hs
+++ b/Database/Persist/Quasi.hs
@@ -1,7 +1,9 @@
-{-# LANGUAGE BangPatterns, CPP #-}
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE CPP #-}
 {-# LANGUAGE RankNTypes #-}
 {-# LANGUAGE PatternGuards #-}
-{-# LANGUAGE StandaloneDeriving, UndecidableInstances #-}
+{-# LANGUAGE StandaloneDeriving #-}
+{-# LANGUAGE UndecidableInstances #-}
 {-# LANGUAGE ViewPatterns #-}
 
 {-|
@@ -435,16 +437,20 @@
 
 import Prelude hiding (lines)
 
-import Control.Applicative hiding (empty)
+import Control.Applicative ( Alternative((<|>)) )
 import Control.Arrow ((&&&))
 import Control.Monad (msum, mplus)
-import Data.Char
+import Data.Char ( isLower, isSpace, isUpper, toLower )
 import Data.List (find, foldl')
 import qualified Data.List.NonEmpty as NEL
 import Data.List.NonEmpty (NonEmpty(..))
 import qualified Data.Map as M
 import Data.Maybe (mapMaybe, fromMaybe, maybeToList, listToMaybe)
 import Data.Monoid (mappend)
+#if !MIN_VERSION_base(4,11,0)
+-- This can be removed when GHC < 8.2.2 isn't supported anymore
+import Data.Semigroup ((<>))
+#endif
 import Data.Text (Text)
 import qualified Data.Text as T
 import Database.Persist.Types
@@ -754,17 +760,17 @@
                                  foreignFieldTexts
                                  fdefs
                          dbname =
-                             unDBName (entityDB pent)
+                             unEntityNameDB (entityDB pent)
                          oldDbName =
-                             unDBName (foreignRefTableDBName fdef)
+                             unEntityNameDB (foreignRefTableDBName fdef)
                       in fdef
                          { foreignFields = map snd fds_ffs
                          , foreignNullable = setNull $ map fst fds_ffs
                          , foreignRefTableDBName =
-                             DBName dbname
+                             EntityNameDB dbname
                          , foreignConstraintNameDBName =
-                             DBName
-                             . T.replace oldDbName dbname . unDBName
+                             ConstraintNameDB
+                             . T.replace oldDbName dbname . unConstraintNameDB
                              $ foreignConstraintNameDBName fdef
                          }
              Nothing ->
@@ -773,20 +779,20 @@
         pentError =
             error $ "could not find table " ++ show (foreignRefTableHaskell fdef)
             ++ " fdef=" ++ show fdef ++ " allnames="
-            ++ show (map (unHaskellName . entityHaskell . unboundEntityDef) unEnts)
+            ++ show (map (unEntityNameHS . entityHaskell . unboundEntityDef) unEnts)
             ++ "\n\nents=" ++ show ents
         pent =
             fromMaybe pentError $ M.lookup (foreignRefTableHaskell fdef) entLookup
         mfdefs = case parentFieldTexts of
             [] -> entitiesPrimary pent
-            _  -> Just $ map (getFd pent . HaskellName) parentFieldTexts
+            _  -> Just $ map (getFd pent . FieldNameHS) parentFieldTexts
 
         setNull :: [FieldDef] -> Bool
         setNull [] = error "setNull: impossible!"
         setNull (fd:fds) = let nullSetting = isNull fd in
           if all ((nullSetting ==) . isNull) fds then nullSetting
             else error $ "foreign key columns must all be nullable or non-nullable"
-                   ++ show (map (unHaskellName . fieldHaskell) (fd:fds))
+                   ++ show (map (unFieldNameHS . fieldHaskell) (fd:fds))
         isNull = (NotNullable /=) . nullable . fieldAttrs
 
         toForeignFields :: Text -> FieldDef
@@ -798,17 +804,17 @@
           where
             fd = getFd ent haskellField
 
-            haskellField = HaskellName fieldText
+            haskellField = FieldNameHS fieldText
             (pfh, pfdb) = (fieldHaskell pfd, fieldDB pfd)
 
             chktypes ffld _fkey pfld =
                 if fieldType ffld == fieldType pfld then Nothing
                   else Just $ "fieldType mismatch: " ++ show (fieldType ffld) ++ ", " ++ show (fieldType pfld)
 
-        getFd :: EntityDef -> HaskellName -> FieldDef
+        getFd :: EntityDef -> FieldNameHS -> FieldDef
         getFd entity t = go (keyAndEntityFields entity)
           where
-            go [] = error $ "foreign key constraint for: " ++ show (unHaskellName $ entityHaskell entity)
+            go [] = error $ "foreign key constraint for: " ++ show (unEntityNameHS $ entityHaskell entity)
                        ++ " unknown column: " ++ show t
             go (f:fs)
                 | fieldHaskell f == t = f
@@ -842,8 +848,8 @@
 mkEntityDef ps name entattribs lines =
   UnboundEntityDef foreigns $
     EntityDef
-        { entityHaskell = HaskellName name'
-        , entityDB = DBName $ getDbName ps name' entattribs
+        { entityHaskell = EntityNameHS name'
+        , entityDB = EntityNameDB $ getDbName ps name' entattribs
         -- idField is the user-specified Id
         -- otherwise useAutoIdField
         -- but, adjust it if the user specified a Primary
@@ -858,7 +864,7 @@
         , entityComments = Nothing
         }
   where
-    entName = HaskellName name'
+    entName = EntityNameHS name'
     (isSum, name') =
         case T.uncons name of
             Just ('+', x) -> (True, x)
@@ -888,7 +894,7 @@
     setFieldComments xs fld =
         fld { fieldComments = Just (T.unlines xs) }
 
-    autoIdField = mkAutoIdField ps entName (DBName `fmap` idName) idSqlType
+    autoIdField = mkAutoIdField ps entName (FieldNameDB `fmap` idName) idSqlType
     idSqlType = maybe SqlInt64 (const $ SqlOther "Primary Key") primaryComposite
 
     setComposite Nothing fd = fd
@@ -902,15 +908,15 @@
   `mappend` show x `mappend` " " `mappend` show y
 just1 x y = x `mplus` y
 
-mkAutoIdField :: PersistSettings -> HaskellName -> Maybe DBName -> SqlType -> FieldDef
+mkAutoIdField :: PersistSettings -> EntityNameHS -> Maybe FieldNameDB -> SqlType -> FieldDef
 mkAutoIdField ps entName idName idSqlType =
     FieldDef
-        { fieldHaskell = HaskellName "Id"
+        { fieldHaskell = FieldNameHS "Id"
         -- this should be modeled as a Maybe
         -- but that sucks for non-ID field
         -- TODO: use a sumtype FieldDef | IdFieldDef
-        , fieldDB = fromMaybe (DBName $ psIdName ps) idName
-        , fieldType = FTTypeCon Nothing $ keyConName $ unHaskellName entName
+        , fieldDB = fromMaybe (FieldNameDB $ psIdName ps) idName
+        , fieldType = FTTypeCon Nothing $ keyConName $ unEntityNameHS entName
         , fieldSqlType = idSqlType
         -- the primary field is actually a reference to the entity
         , fieldReference = ForeignRef entName defaultReferenceTypeCon
@@ -958,8 +964,8 @@
         case parseFieldType typ of
             Left err -> onErr typ err
             Right ft -> Just FieldDef
-                { fieldHaskell = HaskellName n
-                , fieldDB = DBName $ getDbName ps n attrs_
+                { fieldHaskell = FieldNameHS n
+                , fieldDB = FieldNameDB $ getDbName ps n attrs_
                 , fieldType = ft
                 , fieldSqlType = SqlOther $ "SqlType unset for " `mappend` n
                 , fieldAttrs = fieldAttrs_
@@ -1016,7 +1022,7 @@
     addDefaultIdType = takeColsEx ps (field : keyCon : rest ) -- `mappend` setIdName)
     setFieldDef fd = fd
         { fieldReference =
-            ForeignRef (HaskellName tableName) $
+            ForeignRef (EntityNameHS tableName) $
                 if fieldType fd == FTTypeCon Nothing keyCon
                 then defaultReferenceTypeCon
                 else fieldType fd
@@ -1038,7 +1044,7 @@
     (_, attrs) = break ("!" `T.isPrefixOf`) pkcols
     getDef [] t = error $ "Unknown column in primary key constraint: " ++ show t
     getDef (d:ds) t
-        | fieldHaskell d == HaskellName t =
+        | fieldHaskell d == FieldNameHS t =
             if nullable (fieldAttrs d) /= NotNullable
                 then error $ "primary key column cannot be nullable: " ++ show t ++ show fields
                 else d
@@ -1056,9 +1062,9 @@
 takeUniq ps tableName defs (n:rest)
     | not (T.null n) && isUpper (T.head n)
         = UniqueDef
-            (HaskellName n)
+            (ConstraintNameHS n)
             dbName
-            (map (HaskellName &&& getDBName defs) fields)
+            (map (FieldNameHS &&& getDBName defs) fields)
             attrs
   where
     isAttr a =
@@ -1072,22 +1078,22 @@
       break isNonField rest
     attrs = filter isAttr nonFields
     usualDbName =
-      DBName $ psToDBName ps (tableName `T.append` n)
-    sqlName :: Maybe DBName
+      ConstraintNameDB $ psToDBName ps (tableName `T.append` n)
+    sqlName :: Maybe ConstraintNameDB
     sqlName =
       case find isSqlName nonFields of
         Nothing ->
           Nothing
         (Just t) ->
           case drop 1 $ T.splitOn "=" t of
-            (x : _) -> Just (DBName x)
+            (x : _) -> Just (ConstraintNameDB x)
             _ -> Nothing
     dbName = fromMaybe usualDbName sqlName
     getDBName [] t =
       error $ "Unknown column in unique constraint: " ++ show t
               ++ " " ++ show defs ++ show n ++ " " ++ show attrs
     getDBName (d:ds) t
-        | fieldHaskell d == HaskellName t = fieldDB d
+        | fieldHaskell d == FieldNameHS t = fieldDB d
         | otherwise = getDBName ds t
 takeUniq _ tableName _ xs =
   error $ "invalid unique constraint on table["
@@ -1120,13 +1126,13 @@
         go (n:rest) onDelete onUpdate | not (T.null n) && isLower (T.head n)
             = UnboundForeignDef fFields pFields $ ForeignDef
                 { foreignRefTableHaskell =
-                    HaskellName refTableName
+                    EntityNameHS refTableName
                 , foreignRefTableDBName =
-                    DBName $ psToDBName ps refTableName
+                    EntityNameDB $ psToDBName ps refTableName
                 , foreignConstraintNameHaskell =
-                    HaskellName n
+                    ConstraintNameHS n
                 , foreignConstraintNameDBName =
-                    DBName $ psToDBName ps (tableName `T.append` n)
+                    ConstraintNameDB $ psToDBName ps (tableName `T.append` n)
                 , foreignFieldCascade = FieldCascade
                     { fcOnDelete = onDelete
                     , fcOnUpdate = onUpdate
@@ -1200,14 +1206,14 @@
                             Nothing ->
                                 go (this : acc) mupd mdel rest
     nope msg =
-        error $ msg `mappend` ", tokens: " `mappend` show allTokens
+        error $ msg <> ", tokens: " <> show allTokens
 
 parseCascadeAction
     :: CascadePrefix
     -> Text
     -> Maybe CascadeAction
 parseCascadeAction prfx text = do
-    cascadeStr <- T.stripPrefix ("On" `mappend` toPrefix prfx) text
+    cascadeStr <- T.stripPrefix ("On" <> toPrefix prfx) text
     case readEither (T.unpack cascadeStr) of
         Right a ->
             Just a
diff --git a/Database/Persist/Sql.hs b/Database/Persist/Sql.hs
--- a/Database/Persist/Sql.hs
+++ b/Database/Persist/Sql.hs
@@ -30,7 +30,7 @@
 import Database.Persist.Sql.Types
 import Database.Persist.Sql.Types.Internal (IsolationLevel (..))
 import Database.Persist.Sql.Class
-import Database.Persist.Sql.Run hiding (withResourceTimeout, rawAcquireSqlConn)
+import Database.Persist.Sql.Run hiding (rawAcquireSqlConn, rawRunSqlPool)
 import Database.Persist.Sql.Raw
 import Database.Persist.Sql.Migration
 import Database.Persist.Sql.Internal
diff --git a/Database/Persist/Sql/Class.hs b/Database/Persist/Sql/Class.hs
--- a/Database/Persist/Sql/Class.hs
+++ b/Database/Persist/Sql/Class.hs
@@ -41,7 +41,7 @@
 class RawSql a where
     -- | Number of columns that this data type needs and the list
     -- of substitutions for @SELECT@ placeholders @??@.
-    rawSqlCols :: (DBName -> Text) -> a -> (Int, [Text])
+    rawSqlCols :: (Text -> Text) -> a -> (Int, [Text])
 
     -- | A string telling the user why the column count is what
     -- it is.
@@ -70,12 +70,12 @@
     RawSql (Entity record) where
     rawSqlCols escape _ent = (length sqlFields, [intercalate ", " sqlFields])
         where
-          sqlFields = map (((name <> ".") <>) . escape)
+          sqlFields = map (((name <> ".") <>) . escapeWith escape)
               $ map fieldDB
               -- Hacky for a composite key because
               -- it selects the same field multiple times
               $ entityKeyFields entDef ++ entityFields entDef
-          name = escape (entityDB entDef)
+          name = escapeWith escape (entityDB entDef)
           entDef = entityDef (Nothing :: Maybe record)
     rawSqlColCountReason a =
         case fst (rawSqlCols (error "RawSql") a) of
@@ -152,7 +152,7 @@
   => RawSql (EntityWithPrefix prefix record) where
     rawSqlCols escape _ent = (length sqlFields, [intercalate ", " sqlFields])
         where
-          sqlFields = map (((name <> ".") <>) . escape)
+          sqlFields = map (((name <> ".") <>) . escapeWith escape)
               $ map fieldDB
               -- Hacky for a composite key because
               -- it selects the same field multiple times
diff --git a/Database/Persist/Sql/Internal.hs b/Database/Persist/Sql/Internal.hs
--- a/Database/Persist/Sql/Internal.hs
+++ b/Database/Persist/Sql/Internal.hs
@@ -27,7 +27,7 @@
 --
 -- @since 2.11
 data BackendSpecificOverrides = BackendSpecificOverrides
-    { backendSpecificForeignKeyName :: Maybe (DBName -> DBName -> DBName)
+    { backendSpecificForeignKeyName :: Maybe (EntityNameDB -> FieldNameDB -> ConstraintNameDB)
     }
 
 findMaybe :: (a -> Maybe b) -> [a] -> Maybe b
@@ -99,7 +99,7 @@
             , cReference = mkColumnReference fd
             }
 
-    tableName :: DBName
+    tableName :: EntityNameDB
     tableName = entityDB t
 
 
@@ -140,10 +140,10 @@
             , fcOnDelete = del <|> Just Restrict
             }
 
-    ref :: DBName
+    ref :: FieldNameDB
         -> ReferenceDef
         -> [FieldAttr]
-        -> Maybe (DBName, DBName) -- table name, constraint name
+        -> Maybe (EntityNameDB, ConstraintNameDB) -- table name, constraint name
     ref c fe []
         | ForeignRef f _ <- fe =
             Just (resolveTableName allDefs f, refNameFn tableName c)
@@ -152,18 +152,18 @@
     ref c fe (a:as) = case a of
         FieldAttrReference x -> do
             (_, constraintName) <- ref c fe as
-            pure (DBName x, constraintName)
+            pure (EntityNameDB  x, constraintName)
         FieldAttrConstraint x -> do
             (tableName_, _) <- ref c fe as
-            pure (tableName_, DBName x)
+            pure (tableName_, ConstraintNameDB x)
         _ -> ref c fe as
 
-refName :: DBName -> DBName -> DBName
-refName (DBName table) (DBName column) =
-    DBName $ Data.Monoid.mconcat [table, "_", column, "_fkey"]
+refName :: EntityNameDB -> FieldNameDB -> ConstraintNameDB
+refName (EntityNameDB table) (FieldNameDB column) =
+    ConstraintNameDB $ Data.Monoid.mconcat [table, "_", column, "_fkey"]
 
-resolveTableName :: [EntityDef] -> HaskellName -> DBName
-resolveTableName [] (HaskellName hn) = error $ "Table not found: " `Data.Monoid.mappend` T.unpack hn
+resolveTableName :: [EntityDef] -> EntityNameHS -> EntityNameDB
+resolveTableName [] (EntityNameHS t) = error $ "Table not found: " `Data.Monoid.mappend` T.unpack t
 resolveTableName (e:es) hn
     | entityHaskell e == hn = entityDB e
     | otherwise = resolveTableName es hn
diff --git a/Database/Persist/Sql/Orphan/PersistQuery.hs b/Database/Persist/Sql/Orphan/PersistQuery.hs
--- a/Database/Persist/Sql/Orphan/PersistQuery.hs
+++ b/Database/Persist/Sql/Orphan/PersistQuery.hs
@@ -11,7 +11,7 @@
 
 import Control.Exception (throwIO)
 import Control.Monad.IO.Class
-import Control.Monad.Trans.Reader (ReaderT, ask, withReaderT)
+import Control.Monad.Trans.Reader (ReaderT, ask)
 import Data.ByteString.Char8 (readInteger)
 import Data.Conduit
 import qualified Data.Conduit.List as CL
@@ -39,7 +39,7 @@
                     else filterClause False conn filts
         let sql = mconcat
                 [ "SELECT COUNT(*) FROM "
-                , connEscapeName conn $ entityDB t
+                , connEscapeTableName conn t
                 , wher
                 ]
         withRawQuery sql (getFiltsValues conn filts) $ do
@@ -62,7 +62,7 @@
                     else filterClause False conn filts
         let sql = mconcat
                 [ "SELECT EXISTS(SELECT 1 FROM "
-                , connEscapeName conn $ entityDB t
+                , connEscapeTableName conn t
                 , wher
                 , ")"
                 ]
@@ -103,7 +103,7 @@
             [ "SELECT "
             , cols conn
             , " FROM "
-            , connEscapeName conn $ entityDB t
+            , connEscapeTableName conn t
             , wher conn
             , ord conn
             ]
@@ -124,7 +124,7 @@
             [ "SELECT "
             , cols conn
             , " FROM "
-            , connEscapeName conn $ entityDB t
+            , connEscapeTableName conn t
             , wher conn
             , ord conn
             ]
@@ -151,15 +151,15 @@
                 Right k -> return k
                 Left err -> error $ "selectKeysImpl: keyFromValues failed" <> show err
 instance PersistQueryRead SqlReadBackend where
-    count filts = withReaderT persistBackend $ count filts
-    exists filts = withReaderT persistBackend $ exists filts
-    selectSourceRes filts opts = withReaderT persistBackend $ selectSourceRes filts opts
-    selectKeysRes filts opts = withReaderT persistBackend $ selectKeysRes filts opts
+    count filts = withBaseBackend $ count filts
+    exists filts = withBaseBackend $ exists filts
+    selectSourceRes filts opts = withBaseBackend $ selectSourceRes filts opts
+    selectKeysRes filts opts = withBaseBackend $ selectKeysRes filts opts
 instance PersistQueryRead SqlWriteBackend where
-    count filts = withReaderT persistBackend $ count filts
-    exists filts = withReaderT persistBackend $ exists filts
-    selectSourceRes filts opts = withReaderT persistBackend $ selectSourceRes filts opts
-    selectKeysRes filts opts = withReaderT persistBackend $ selectKeysRes filts opts
+    count filts = withBaseBackend $ count filts
+    exists filts = withBaseBackend $ exists filts
+    selectSourceRes filts opts = withBaseBackend $ selectSourceRes filts opts
+    selectKeysRes filts opts = withBaseBackend $ selectKeysRes filts opts
 
 instance PersistQueryWrite SqlBackend where
     deleteWhere filts = do
@@ -169,8 +169,8 @@
         _ <- updateWhereCount filts upds
         return ()
 instance PersistQueryWrite SqlWriteBackend where
-    deleteWhere filts = withReaderT persistBackend $ deleteWhere filts
-    updateWhere filts upds = withReaderT persistBackend $ updateWhere filts upds
+    deleteWhere filts = withBaseBackend $ deleteWhere filts
+    updateWhere filts upds = withBaseBackend $ updateWhere filts upds
 
 -- | Same as 'deleteWhere', but returns the number of rows affected.
 --
@@ -178,7 +178,7 @@
 deleteWhereCount :: (PersistEntity val, MonadIO m, PersistEntityBackend val ~ SqlBackend, BackendCompatible SqlBackend backend)
                  => [Filter val]
                  -> ReaderT backend m Int64
-deleteWhereCount filts = withReaderT projectBackend $ do
+deleteWhereCount filts = withCompatibleBackend $ do
     conn <- ask
     let t = entityDef $ dummyFromFilts filts
     let wher = if null filts
@@ -186,7 +186,7 @@
                 else filterClause False conn filts
         sql = mconcat
             [ "DELETE FROM "
-            , connEscapeName conn $ entityDB t
+            , connEscapeTableName conn t
             , wher
             ]
     rawExecuteCount sql $ getFiltsValues conn filts
@@ -199,14 +199,14 @@
                  -> [Update val]
                  -> ReaderT backend m Int64
 updateWhereCount _ [] = return 0
-updateWhereCount filts upds = withReaderT projectBackend $ do
+updateWhereCount filts upds = withCompatibleBackend $ do
     conn <- ask
     let wher = if null filts
                 then ""
                 else filterClause False conn filts
     let sql = mconcat
             [ "UPDATE "
-            , connEscapeName conn $ entityDB t
+            , connEscapeTableName conn t
             , " SET "
             , T.intercalate "," $ map (mkUpdateText conn) upds
             , wher
@@ -217,7 +217,7 @@
   where
     t = entityDef $ dummyFromFilts filts
 
-fieldName ::  forall record typ. (PersistEntity record, PersistEntityBackend record ~ SqlBackend) => EntityField record typ -> DBName
+fieldName ::  forall record typ. (PersistEntity record, PersistEntityBackend record ~ SqlBackend) => EntityField record typ -> FieldNameDB
 fieldName f = fieldDB $ persistFieldDef f
 
 dummyFromFilts :: [Filter v] -> Maybe v
@@ -264,23 +264,23 @@
                     else
                       case (allVals, pfilter, isCompFilter pfilter) of
                         ([PersistList xs], Eq, _) ->
-                           let sqlcl=T.intercalate " and " (map (\a -> connEscapeName conn (fieldDB a) <> showSqlFilter pfilter <> "? ")  (compositeFields pdef))
+                           let sqlcl=T.intercalate " and " (map (\a -> connEscapeFieldName conn (fieldDB a) <> showSqlFilter pfilter <> "? ")  (compositeFields pdef))
                            in (wrapSql sqlcl,xs)
                         ([PersistList xs], Ne, _) ->
-                           let sqlcl=T.intercalate " or " (map (\a -> connEscapeName conn (fieldDB a) <> showSqlFilter pfilter <> "? ")  (compositeFields pdef))
+                           let sqlcl=T.intercalate " or " (map (\a -> connEscapeFieldName conn (fieldDB a) <> showSqlFilter pfilter <> "? ")  (compositeFields pdef))
                            in (wrapSql sqlcl,xs)
                         (_, In, _) ->
                            let xxs = transpose (map fromPersistList allVals)
-                               sqls=map (\(a,xs) -> connEscapeName conn (fieldDB a) <> showSqlFilter pfilter <> "(" <> T.intercalate "," (replicate (length xs) " ?") <> ") ") (zip (compositeFields pdef) xxs)
+                               sqls=map (\(a,xs) -> connEscapeFieldName conn (fieldDB a) <> showSqlFilter pfilter <> "(" <> T.intercalate "," (replicate (length xs) " ?") <> ") ") (zip (compositeFields pdef) xxs)
                            in (wrapSql (T.intercalate " and " (map wrapSql sqls)), concat xxs)
                         (_, NotIn, _) ->
                            let xxs = transpose (map fromPersistList allVals)
-                               sqls=map (\(a,xs) -> connEscapeName conn (fieldDB a) <> showSqlFilter pfilter <> "(" <> T.intercalate "," (replicate (length xs) " ?") <> ") ") (zip (compositeFields pdef) xxs)
+                               sqls=map (\(a,xs) -> connEscapeFieldName conn (fieldDB a) <> showSqlFilter pfilter <> "(" <> T.intercalate "," (replicate (length xs) " ?") <> ") ") (zip (compositeFields pdef) xxs)
                            in (wrapSql (T.intercalate " or " (map wrapSql sqls)), concat xxs)
                         ([PersistList xs], _, True) ->
                            let zs = tail (inits (compositeFields pdef))
                                sql1 = map (\b -> wrapSql (T.intercalate " and " (map (\(i,a) -> sql2 (i==length b) a) (zip [1..] b)))) zs
-                               sql2 islast a = connEscapeName conn (fieldDB a) <> (if islast then showSqlFilter pfilter else showSqlFilter Eq) <> "? "
+                               sql2 islast a = connEscapeFieldName conn (fieldDB a) <> (if islast then showSqlFilter pfilter else showSqlFilter Eq) <> "? "
                                sqlcl = T.intercalate " or " sql1
                            in (wrapSql sqlcl, concat (tail (inits xs)))
                         (_, BackendSpecificFilter _, _) -> error "unhandled type BackendSpecificFilter for composite/non id primary keys"
@@ -362,13 +362,12 @@
         isNull = PersistNull `elem` allVals
         notNullVals = filter (/= PersistNull) allVals
         allVals = filterValueToPersistValues value
-        tn = connEscapeName conn $ entityDB
-           $ entityDef $ dummyFromFilts [Filter field value pfilter]
+        tn = connEscapeTableName conn $ entityDef $ dummyFromFilts [Filter field value pfilter]
         name =
             (if includeTable
                 then ((tn <> ".") <>)
                 else id)
-            $ connEscapeName conn $ fieldName field
+            $ connEscapeFieldName conn (fieldName field)
         qmarks = case value of
                     FilterValue{} -> "(?)"
                     UnsafeValue{} -> "(?)"
@@ -409,7 +408,7 @@
     dummyFromOrder :: SelectOpt a -> Maybe a
     dummyFromOrder _ = Nothing
 
-    tn = connEscapeName conn $ entityDB $ entityDef $ dummyFromOrder o
+    tn = connEscapeTableName conn (entityDef $ dummyFromOrder o)
 
     name :: (PersistEntityBackend record ~ SqlBackend, PersistEntity record)
          => EntityField record typ -> Text
@@ -417,7 +416,7 @@
         (if includeTable
             then ((tn <> ".") <>)
             else id)
-        $ connEscapeName conn $ fieldName x
+        $ connEscapeFieldName conn (fieldName x)
 
 -- | Generates sql for limit and offset for postgres, sqlite and mysql.
 decorateSQLWithLimitOffset::Text -> (Int,Int) -> Bool -> Text -> Text
diff --git a/Database/Persist/Sql/Orphan/PersistStore.hs b/Database/Persist/Sql/Orphan/PersistStore.hs
--- a/Database/Persist/Sql/Orphan/PersistStore.hs
+++ b/Database/Persist/Sql/Orphan/PersistStore.hs
@@ -83,12 +83,12 @@
              , BackendCompatible SqlBackend backend
              , Monad m
              ) => record -> ReaderT backend m Text
-getTableName rec = withReaderT projectBackend $ do
+getTableName rec = withCompatibleBackend $ do
     conn <- ask
-    return $ connEscapeName conn $ tableDBName rec
+    return $ connEscapeTableName conn (entityDef $ Just rec)
 
 -- | useful for a backend to implement tableName by adding escaping
-tableDBName :: (PersistEntity record) => record -> DBName
+tableDBName :: (PersistEntity record) => record -> EntityNameDB
 tableDBName rec = entityDB $ entityDef (Just rec)
 
 -- | get the SQL string for the field that an EntityField represents
@@ -103,12 +103,12 @@
              , Monad m
              )
              => EntityField record typ -> ReaderT backend m Text
-getFieldName rec = withReaderT projectBackend $ do
+getFieldName rec = withCompatibleBackend $ do
     conn <- ask
-    return $ connEscapeName conn $ fieldDBName rec
+    return $ connEscapeFieldName conn (fieldDB $ persistFieldDef rec)
 
 -- | useful for a backend to implement fieldName by adding escaping
-fieldDBName :: forall record typ. (PersistEntity record) => EntityField record typ -> DBName
+fieldDBName :: forall record typ. (PersistEntity record) => EntityField record typ -> FieldNameDB
 fieldDBName = fieldDB . persistFieldDef
 
 
@@ -143,7 +143,7 @@
         let wher = whereStmtForKey conn k
         let sql = T.concat
                 [ "UPDATE "
-                , connEscapeName conn $ tableDBName $ recordTypeFromKey k
+                , connEscapeTableName conn (entityDef $ Just $ recordTypeFromKey k)
                 , " SET "
                 , T.intercalate "," $ map (mkUpdateText conn) upds
                 , " WHERE "
@@ -232,9 +232,9 @@
           let valss = map mkInsertValues vals
           let sql = T.concat
                   [ "INSERT INTO "
-                  , connEscapeName conn (entityDB t)
+                  , connEscapeTableName conn t
                   , "("
-                  , T.intercalate "," $ map (connEscapeName conn . fieldDB) $ entityFields t
+                  , T.intercalate "," $ map (connEscapeFieldName conn . fieldDB) $ entityFields t
                   , ") VALUES ("
                   , T.intercalate "),(" $ replicate (length valss) $ T.intercalate "," $ map (const "?") (entityFields t)
                   , ")"
@@ -247,7 +247,7 @@
         let wher = whereStmtForKey conn k
         let sql = T.concat
                 [ "UPDATE "
-                , connEscapeName conn (entityDB t)
+                , connEscapeTableName conn t
                 , " SET "
                 , T.intercalate "," (map (go conn . fieldDB) $ entityFields t)
                 , " WHERE "
@@ -256,7 +256,7 @@
             vals = mkInsertValues val `mappend` keyToValues k
         rawExecute sql vals
       where
-        go conn x = connEscapeName conn x `T.append` "=?"
+        go conn x = connEscapeFieldName conn x `T.append` "=?"
 
     insertKey k v = insrepHelper "INSERT" [Entity k v]
 
@@ -296,21 +296,21 @@
         wher conn = whereStmtForKey conn k
         sql conn = T.concat
             [ "DELETE FROM "
-            , connEscapeName conn $ tableDBName $ recordTypeFromKey k
+            , connEscapeTableName conn (entityDef $ Just $ recordTypeFromKey k)
             , " WHERE "
             , wher conn
             ]
 instance PersistStoreWrite SqlWriteBackend where
-    insert v = withReaderT persistBackend $ insert v
-    insertMany vs = withReaderT persistBackend $ insertMany vs
-    insertMany_ vs = withReaderT persistBackend $ insertMany_ vs
-    insertEntityMany vs = withReaderT persistBackend $ insertEntityMany vs
-    insertKey k v = withReaderT persistBackend $ insertKey k v
-    repsert k v = withReaderT persistBackend $ repsert k v
-    replace k v = withReaderT persistBackend $ replace k v
-    delete k = withReaderT persistBackend $ delete k
-    update k upds = withReaderT persistBackend $ update k upds
-    repsertMany krs = withReaderT persistBackend $ repsertMany krs
+    insert v = withBaseBackend $ insert v
+    insertMany vs = withBaseBackend $ insertMany vs
+    insertMany_ vs = withBaseBackend $ insertMany_ vs
+    insertEntityMany vs = withBaseBackend $ insertEntityMany vs
+    insertKey k v = withBaseBackend $ insertKey k v
+    repsert k v = withBaseBackend $ repsert k v
+    replace k v = withBaseBackend $ replace k v
+    delete k = withBaseBackend $ delete k
+    update k upds = withBaseBackend $ update k upds
+    repsertMany krs = withBaseBackend $ repsertMany krs
 
 instance PersistStoreRead SqlBackend where
     get k = do
@@ -328,7 +328,7 @@
                 [ "SELECT "
                 , cols conn
                 , " FROM "
-                , connEscapeName conn $ entityDB t
+                , connEscapeTableName conn t
                 , " WHERE "
                 , wher
                 ]
@@ -341,11 +341,11 @@
             return $ Map.fromList $ fmap (\e -> (entityKey e, entityVal e)) es
 
 instance PersistStoreRead SqlReadBackend where
-    get k = withReaderT persistBackend $ get k
-    getMany ks = withReaderT persistBackend $ getMany ks
+    get k = withBaseBackend $ get k
+    getMany ks = withBaseBackend $ getMany ks
 instance PersistStoreRead SqlWriteBackend where
-    get k = withReaderT persistBackend $ get k
-    getMany ks = withReaderT persistBackend $ getMany ks
+    get k = withBaseBackend $ get k
+    getMany ks = withBaseBackend $ getMany ks
 
 dummyFromKey :: Key record -> Maybe record
 dummyFromKey = Just . recordTypeFromKey
@@ -367,7 +367,7 @@
     sql conn columnNames = T.concat
         [ command
         , " INTO "
-        , connEscapeName conn (entityDB entDef)
+        , connEscapeTableName conn entDef
         , "("
         , T.intercalate "," columnNames
         , ") VALUES ("
diff --git a/Database/Persist/Sql/Orphan/PersistUnique.hs b/Database/Persist/Sql/Orphan/PersistUnique.hs
--- a/Database/Persist/Sql/Orphan/PersistUnique.hs
+++ b/Database/Persist/Sql/Orphan/PersistUnique.hs
@@ -6,7 +6,7 @@
 
 import Control.Exception (throwIO)
 import Control.Monad.IO.Class (liftIO)
-import Control.Monad.Trans.Reader (ask, withReaderT)
+import Control.Monad.Trans.Reader (ask)
 import qualified Data.Conduit.List as CL
 import Data.Function (on)
 import Data.List (nubBy)
@@ -25,9 +25,8 @@
 instance PersistUniqueWrite SqlBackend where
     upsertBy uniqueKey record updates = do
       conn <- ask
-      let escape = connEscapeName conn
-      let refCol n = T.concat [escape (entityDB t), ".", n]
-      let mkUpdateText = mkUpdateText' escape refCol
+      let refCol n = T.concat [connEscapeTableName conn t, ".", n]
+      let mkUpdateText = mkUpdateText' (connEscapeFieldName conn) refCol
       case connUpsertSql conn of
         Just upsertSql -> case updates of
                             [] -> defaultUpsertBy uniqueKey record updates
@@ -53,11 +52,11 @@
       where
         t = entityDef $ dummyFromUnique uniq
         go = map snd . persistUniqueToFieldNames
-        go' conn x = connEscapeName conn x `mappend` "=?"
+        go' conn x = connEscapeFieldName conn x `mappend` "=?"
         sql conn =
             T.concat
                 [ "DELETE FROM "
-                , connEscapeName conn $ entityDB t
+                , connEscapeTableName conn t
                 , " WHERE "
                 , T.intercalate " AND " $ map (go' conn) $ go uniq]
 
@@ -79,9 +78,9 @@
                 Nothing -> defaultPutMany rs
 
 instance PersistUniqueWrite SqlWriteBackend where
-    deleteBy uniq = withReaderT persistBackend $ deleteBy uniq
-    upsert rs us = withReaderT persistBackend $ upsert rs us
-    putMany rs = withReaderT persistBackend $ putMany rs
+    deleteBy uniq = withBaseBackend $ deleteBy uniq
+    upsert rs us = withBaseBackend $ upsert rs us
+    putMany rs = withBaseBackend $ putMany rs
 
 instance PersistUniqueRead SqlBackend where
     getBy uniq = do
@@ -91,7 +90,7 @@
                     [ "SELECT "
                     , T.intercalate "," $ dbColumns conn t
                     , " FROM "
-                    , connEscapeName conn $ entityDB t
+                    , connEscapeTableName conn t
                     , " WHERE "
                     , sqlClause conn]
             uvals = persistUniqueToValues uniq
@@ -108,15 +107,15 @@
       where
         sqlClause conn =
             T.intercalate " AND " $ map (go conn) $ toFieldNames' uniq
-        go conn x = connEscapeName conn x `mappend` "=?"
+        go conn x = connEscapeFieldName conn x `mappend` "=?"
         t = entityDef $ dummyFromUnique uniq
         toFieldNames' = map snd . persistUniqueToFieldNames
 
 instance PersistUniqueRead SqlReadBackend where
-    getBy uniq = withReaderT persistBackend $ getBy uniq
+    getBy uniq = withBaseBackend $ getBy uniq
 
 instance PersistUniqueRead SqlWriteBackend where
-    getBy uniq = withReaderT persistBackend $ getBy uniq
+    getBy uniq = withBaseBackend $ getBy uniq
 
 dummyFromUnique :: Unique v -> Maybe v
 dummyFromUnique _ = Nothing
diff --git a/Database/Persist/Sql/Raw.hs b/Database/Persist/Sql/Raw.hs
--- a/Database/Persist/Sql/Raw.hs
+++ b/Database/Persist/Sql/Raw.hs
@@ -231,7 +231,7 @@
 
       run params = do
         conn <- projectBackend `liftM` ask
-        let (colCount, colSubsts) = rawSqlCols (connEscapeName conn) x
+        let (colCount, colSubsts) = rawSqlCols (connEscapeRawName conn) x
         withStmt' colSubsts params $ firstRow colCount
 
       firstRow colCount = do
diff --git a/Database/Persist/Sql/Run.hs b/Database/Persist/Sql/Run.hs
--- a/Database/Persist/Sql/Run.hs
+++ b/Database/Persist/Sql/Run.hs
@@ -1,8 +1,6 @@
 {-# LANGUAGE ScopedTypeVariables #-}
 module Database.Persist.Sql.Run where
 
-import Control.Exception (bracket, mask, onException)
-import Control.Monad (liftM)
 import Control.Monad.IO.Unlift
 import qualified UnliftIO.Exception as UE
 import Control.Monad.Logger.CallStack
@@ -12,98 +10,30 @@
 import Control.Monad.Trans.Resource
 import Data.Acquire (Acquire, ReleaseType(..), mkAcquireType, with)
 import Data.IORef (readIORef)
-import Data.Pool (Pool, LocalPool)
+import Data.Pool (Pool)
 import Data.Pool as P
 import qualified Data.Map as Map
 import qualified Data.Text as T
-import System.Timeout (timeout)
 
 import Database.Persist.Class.PersistStore
 import Database.Persist.Sql.Types
 import Database.Persist.Sql.Types.Internal (IsolationLevel)
 import Database.Persist.Sql.Raw
 
--- | The returned 'Acquire' gets a connection from the pool, but does __NOT__
--- start a new transaction. Used to implement 'acquireSqlConnFromPool' and
--- 'acquireSqlConnFromPoolWithIsolation', this is useful for performing actions
--- on a connection that cannot be done within a transaction, such as VACUUM in
--- Sqlite.
---
--- @since 2.10.5
-unsafeAcquireSqlConnFromPool
-    :: forall backend m
-     . (MonadReader (Pool backend) m, BackendCompatible SqlBackend backend)
-    => m (Acquire backend)
-unsafeAcquireSqlConnFromPool = do
-    pool <- MonadReader.ask
-
-    let freeConn :: (backend, LocalPool backend) -> ReleaseType -> IO ()
-        freeConn (res, localPool) relType = case relType of
-            ReleaseException -> P.destroyResource pool localPool res
-            _ -> P.putResource localPool res
-
-    return $ fst <$> mkAcquireType (P.takeResource pool) freeConn
-
-{-# DEPRECATED unsafeAcquireSqlConnFromPool "The Pool ~> Acquire functions are unpredictable and may result in resource leaks with asynchronous exceptions. They will be removed in 2.12. If you need them, please file an issue and we'll try to help get you sorted. See issue #1199 on GitHub for the debugging log." #-}
-
--- | The returned 'Acquire' gets a connection from the pool, starts a new
--- transaction and gives access to the prepared connection.
---
--- When the acquired connection is released the transaction is committed and
--- the connection returned to the pool.
---
--- Upon an exception the transaction is rolled back and the connection
--- destroyed.
---
--- This is equivalent to 'runSqlPool' but does not incur the 'MonadUnliftIO'
--- constraint, meaning it can be used within, for example, a 'Conduit'
--- pipeline.
---
--- @since 2.10.5
-acquireSqlConnFromPool
-    :: (MonadReader (Pool backend) m, BackendCompatible SqlBackend backend)
-    => m (Acquire backend)
-acquireSqlConnFromPool = do
-    connFromPool <- unsafeAcquireSqlConnFromPool
-    return $ connFromPool >>= acquireSqlConn
-
-{-# DEPRECATED acquireSqlConnFromPool "The Pool ~> Acquire functions are unpredictable and may result in resource leaks with asynchronous exceptions. They will be removed in 2.12. If you need them, please file an issue and we'll try to help get you sorted. See issue #1199 on GitHub for the debugging log." #-}
-
--- | Like 'acquireSqlConnFromPool', but lets you specify an explicit isolation
--- level.
---
--- @since 2.10.5
-acquireSqlConnFromPoolWithIsolation
-    :: (MonadReader (Pool backend) m, BackendCompatible SqlBackend backend)
-    => IsolationLevel -> m (Acquire backend)
-acquireSqlConnFromPoolWithIsolation isolation = do
-    connFromPool <- unsafeAcquireSqlConnFromPool
-    return $ connFromPool >>= acquireSqlConnWithIsolation isolation
-
-{-# DEPRECATED acquireSqlConnFromPoolWithIsolation "The Pool ~> Acquire functions are unpredictable and may result in resource leaks with asynchronous exceptions. They will be removed in 2.12. If you need them, please file an issue and we'll try to help get you sorted. See issue #1199 on GitHub for the debugging log." #-}
-
 -- | Get a connection from the pool, run the given action, and then return the
 -- connection to the pool.
 --
+-- This function performs the given action in a transaction. If an
+-- exception occurs during the action, then the transaction is rolled back.
+--
 -- Note: This function previously timed out after 2 seconds, but this behavior
 -- was buggy and caused more problems than it solved. Since version 2.1.2, it
 -- performs no timeout checks.
 runSqlPool
     :: forall backend m a. (MonadUnliftIO m, BackendCompatible SqlBackend backend)
     => ReaderT backend m a -> Pool backend -> m a
-runSqlPool r pconn =
-    withRunInIO $ \runInIO ->
-    withResource pconn $ \conn ->
-    UE.mask $ \restore -> do
-        let sqlBackend = projectBackend conn
-        let getter = getStmtConn sqlBackend
-        restore $ connBegin sqlBackend getter Nothing
-        a <- restore (runInIO (runReaderT r conn))
-            `UE.catchAny` \e -> do
-                restore $ connRollback sqlBackend getter
-                UE.throwIO e
-        restore $ connCommit sqlBackend getter
-        pure a
+runSqlPool r pconn = do
+    rawRunSqlPool r pconn Nothing
 
 -- | Like 'runSqlPool', but supports specifying an isolation level.
 --
@@ -112,41 +42,69 @@
     :: forall backend m a. (MonadUnliftIO m, BackendCompatible SqlBackend backend)
     => ReaderT backend m a -> Pool backend -> IsolationLevel -> m a
 runSqlPoolWithIsolation r pconn i =
-    withRunInIO $ \runInIO ->
-    withResource pconn $ \conn ->
-    mask $ \restore -> do
+    rawRunSqlPool r pconn (Just i)
+
+-- | Like 'runSqlPool', but does not surround the action in a transaction.
+-- This action might leave your database in a weird state.
+--
+-- @since 2.12.0.0
+runSqlPoolNoTransaction
+    :: forall backend m a. (MonadUnliftIO m, BackendCompatible SqlBackend backend)
+    => ReaderT backend m a -> Pool backend -> Maybe IsolationLevel -> m a
+runSqlPoolNoTransaction r pconn i =
+    runSqlPoolWithHooks r pconn i (\_ -> pure ()) (\_ -> pure ()) (\_ _ -> pure ())
+
+rawRunSqlPool
+    :: forall backend m a. (MonadUnliftIO m, BackendCompatible SqlBackend backend)
+    => ReaderT backend m a -> Pool backend -> Maybe IsolationLevel -> m a
+rawRunSqlPool r pconn mi =
+    runSqlPoolWithHooks r pconn mi before after onException
+  where
+    before conn = do
         let sqlBackend = projectBackend conn
         let getter = getStmtConn sqlBackend
-        restore $ connBegin sqlBackend getter (Just i)
+        liftIO $ connBegin sqlBackend getter mi
+    after conn = do
+        let sqlBackend = projectBackend conn
+        let getter = getStmtConn sqlBackend
+        liftIO $ connCommit sqlBackend getter
+    onException conn _ = do
+        let sqlBackend = projectBackend conn
+        let getter = getStmtConn sqlBackend
+        liftIO $ connRollback sqlBackend getter
+
+-- | This function is how 'runSqlPool' and 'runSqlPoolNoTransaction' are
+-- defined. In addition to the action to be performed and the 'Pool' of
+-- conections to use, we give you the opportunity to provide three actions
+-- - initialize, afterwards, and onException.
+--
+-- @since 2.12.0.0
+runSqlPoolWithHooks
+    :: forall backend m a before after onException. (MonadUnliftIO m, BackendCompatible SqlBackend backend)
+    => ReaderT backend m a
+    -> Pool backend
+    -> Maybe IsolationLevel
+    -> (backend -> m before)
+    -- ^ Run this action immediately before the action is performed.
+    -> (backend -> m after)
+    -- ^ Run this action immediately after the action is completed.
+    -> (backend -> UE.SomeException -> m onException)
+    -- ^ This action is performed when an exception is received. The
+    -- exception is provided as a convenience - it is rethrown once this
+    -- cleanup function is complete.
+    -> m a
+runSqlPoolWithHooks r pconn i before after onException =
+    withRunInIO $ \runInIO ->
+    withResource pconn $ \conn ->
+    UE.mask $ \restore -> do
+        _ <- restore $ runInIO $ before conn
         a <- restore (runInIO (runReaderT r conn))
             `UE.catchAny` \e -> do
-                restore $ connRollback sqlBackend getter
+                _ <- restore $ runInIO $ onException conn e
                 UE.throwIO e
-        restore $ connCommit sqlBackend getter
+        _ <- restore $ runInIO $ after conn
         pure a
 
--- | Like 'withResource', but times out the operation if resource
--- allocation does not complete within the given timeout period.
---
--- @since 2.0.0
-withResourceTimeout
-  :: forall a m b.  (MonadUnliftIO m)
-  => Int -- ^ Timeout period in microseconds
-  -> Pool a
-  -> (a -> m b)
-  -> m (Maybe b)
-{-# SPECIALIZE withResourceTimeout :: Int -> Pool a -> (a -> IO b) -> IO (Maybe b) #-}
-withResourceTimeout ms pool act = withRunInIO $ \runInIO -> mask $ \restore -> do
-    mres <- timeout ms $ takeResource pool
-    case mres of
-        Nothing -> runInIO $ return (Nothing :: Maybe b)
-        Just (resource, local) -> do
-            ret <- restore (runInIO (liftM Just $ act resource)) `onException`
-                    destroyResource pool local resource
-            putResource local resource
-            return ret
-{-# INLINABLE withResourceTimeout #-}
-
 rawAcquireSqlConn
     :: forall backend m
      . (MonadReader backend m, BackendCompatible SqlBackend backend)
@@ -164,7 +122,8 @@
 
         finishTransaction :: backend -> ReleaseType -> IO ()
         finishTransaction _ relType = case relType of
-            ReleaseException -> connRollback rawConn getter
+            ReleaseException -> do
+                connRollback rawConn getter
             _ -> connCommit rawConn getter
 
     return $ mkAcquireType beginTransaction finishTransaction
@@ -220,7 +179,7 @@
 liftSqlPersistMPool x pool = liftIO (runSqlPersistMPool x pool)
 
 withSqlPool
-    :: forall backend m a. (MonadLogger m, MonadUnliftIO m, BackendCompatible SqlBackend backend)
+    :: forall backend m a. (MonadLoggerIO m, MonadUnliftIO m, BackendCompatible SqlBackend backend)
     => (LogFunc -> IO backend) -- ^ create a new connection
     -> Int -- ^ connection count
     -> (Pool backend -> m a)
@@ -232,18 +191,18 @@
 --
 -- @since 2.11.0.0
 withSqlPoolWithConfig
-    :: forall backend m a. (MonadLogger m, MonadUnliftIO m, BackendCompatible SqlBackend backend)
+    :: forall backend m a. (MonadLoggerIO m, MonadUnliftIO m, BackendCompatible SqlBackend backend)
     => (LogFunc -> IO backend) -- ^ Function to create a new connection
     -> ConnectionPoolConfig
     -> (Pool backend -> m a)
     -> m a
-withSqlPoolWithConfig mkConn poolConfig f = withUnliftIO $ \u -> bracket
+withSqlPoolWithConfig mkConn poolConfig f = withUnliftIO $ \u -> UE.bracket
     (unliftIO u $ createSqlPoolWithConfig mkConn poolConfig)
     destroyAllResources
     (unliftIO u . f)
 
 createSqlPool
-    :: forall backend m. (MonadLogger m, MonadUnliftIO m, BackendCompatible SqlBackend backend)
+    :: forall backend m. (MonadLoggerIO m, MonadUnliftIO m, BackendCompatible SqlBackend backend)
     => (LogFunc -> IO backend)
     -> Int
     -> m (Pool backend)
@@ -253,18 +212,20 @@
 --
 -- @since 2.11.0.0
 createSqlPoolWithConfig
-    :: forall m backend. (MonadLogger m, MonadUnliftIO m, BackendCompatible SqlBackend backend)
+    :: forall m backend. (MonadLoggerIO m, MonadUnliftIO m, BackendCompatible SqlBackend backend)
     => (LogFunc -> IO backend) -- ^ Function to create a new connection
     -> ConnectionPoolConfig
     -> m (Pool backend)
 createSqlPoolWithConfig mkConn config = do
-    logFunc <- askLogFunc
+    logFunc <- askLoggerIO
     -- Resource pool will swallow any exceptions from close. We want to log
     -- them instead.
     let loggedClose :: backend -> IO ()
-        loggedClose backend = close' backend `UE.catchAny` \e -> runLoggingT
-          (logError $ T.pack $ "Error closing database connection in pool: " ++ show e)
-          logFunc
+        loggedClose backend = close' backend `UE.catchAny` \e -> do
+            runLoggingT
+              (logError $ T.pack $ "Error closing database connection in pool: " ++ show e)
+              logFunc
+            UE.throwIO e
     liftIO $ createPool
         (mkConn logFunc)
         loggedClose
@@ -272,16 +233,6 @@
         (connectionPoolConfigIdleTimeout config)
         (connectionPoolConfigSize config)
 
--- NOTE: This function is a terrible, ugly hack. It would be much better to
--- just clean up monad-logger.
---
--- FIXME: in a future release, switch over to the new askLoggerIO function
--- added in monad-logger 0.3.10. That function was not available at the time
--- this code was written.
-askLogFunc :: forall m. (MonadUnliftIO m, MonadLogger m) => m LogFunc
-askLogFunc = withRunInIO $ \run ->
-    return $ \a b c d -> run (monadLoggerLog a b c d)
-
 -- | Create a connection and run sql queries within it. This function
 -- automatically closes the connection on it's completion.
 --
@@ -335,11 +286,11 @@
 --
 
 withSqlConn
-    :: forall backend m a. (MonadUnliftIO m, MonadLogger m, BackendCompatible SqlBackend backend)
+    :: forall backend m a. (MonadUnliftIO m, MonadLoggerIO m, BackendCompatible SqlBackend backend)
     => (LogFunc -> IO backend) -> (backend -> m a) -> m a
 withSqlConn open f = do
-    logFunc <- askLogFunc
-    withRunInIO $ \run -> bracket
+    logFunc <- askLoggerIO
+    withRunInIO $ \run -> UE.bracket
       (open logFunc)
       close'
       (run . f)
diff --git a/Database/Persist/Sql/Types.hs b/Database/Persist/Sql/Types.hs
--- a/Database/Persist/Sql/Types.hs
+++ b/Database/Persist/Sql/Types.hs
@@ -23,12 +23,12 @@
 import Data.Time (NominalDiffTime)
 
 data Column = Column
-    { cName      :: !DBName
+    { cName      :: !FieldNameDB
     , cNull      :: !Bool
     , cSqlType   :: !SqlType
     , cDefault   :: !(Maybe Text)
     , cGenerated :: !(Maybe Text)
-    , cDefaultConstraintName   :: !(Maybe DBName)
+    , cDefaultConstraintName   :: !(Maybe ConstraintNameDB)
     , cMaxLen    :: !(Maybe Integer)
     , cReference :: !(Maybe ColumnReference)
     }
@@ -38,11 +38,11 @@
 --
 -- @since 2.11.0.0
 data ColumnReference = ColumnReference
-    { crTableName :: !DBName
+    { crTableName :: !EntityNameDB
     -- ^ The table name that the
     --
     -- @since 2.11.0.0
-    , crConstraintName :: !DBName
+    , crConstraintName :: !ConstraintNameDB
     -- ^ The name of the foreign key constraint.
     --
     -- @since 2.11.0.0
diff --git a/Database/Persist/Sql/Types/Internal.hs b/Database/Persist/Sql/Types/Internal.hs
--- a/Database/Persist/Sql/Types/Internal.hs
+++ b/Database/Persist/Sql/Types/Internal.hs
@@ -101,7 +101,7 @@
     -- ^ SQL for inserting many rows and returning their primary keys, for
     -- backends that support this functionality. If 'Nothing', rows will be
     -- inserted one-at-a-time using 'connInsertSql'.
-    , connUpsertSql :: Maybe (EntityDef -> NonEmpty (HaskellName,DBName) -> Text -> Text)
+    , connUpsertSql :: Maybe (EntityDef -> NonEmpty (FieldNameHS, FieldNameDB) -> Text -> Text)
     -- ^ Some databases support performing UPSERT _and_ RETURN entity
     -- in a single call.
     --
@@ -147,9 +147,21 @@
     -- ^ A function to commit a transaction to the underlying database.
     , connRollback :: (Text -> IO Statement) -> IO ()
     -- ^ A function to roll back a transaction on the underlying database.
-    , connEscapeName :: DBName -> Text
-    -- ^ A function to escape a name for the underlying database. MySQL
-    -- uses backtick characters, while postgresql uses double quoes.
+    , connEscapeFieldName :: FieldNameDB -> Text
+    -- ^ A function to extract and escape the name of the column corresponding
+    -- to the provided field.
+    --
+    -- @since 2.12.0.0
+    , connEscapeTableName :: EntityDef -> Text
+    -- ^ A function to extract and escape the name of the table corresponding
+    -- to the provided entity. PostgreSQL uses this to support schemas.
+    --
+    -- @since 2.12.0.0
+    , connEscapeRawName :: Text -> Text
+    -- ^ A function to escape raw DB identifiers. MySQL uses backticks, while
+    -- PostgreSQL uses quotes, and so on.
+    --
+    -- @since 2.12.0.0
     , connNoLimit :: Text
     , connRDBMS :: Text
     -- ^ A tag displaying what database the 'SqlBackend' is for. Can be
diff --git a/Database/Persist/Sql/Util.hs b/Database/Persist/Sql/Util.hs
--- a/Database/Persist/Sql/Util.hs
+++ b/Database/Persist/Sql/Util.hs
@@ -26,23 +26,24 @@
 import qualified Data.Text as T
 
 import Database.Persist (
-    Entity(Entity), EntityDef, EntityField, HaskellName(HaskellName)
+    Entity(Entity), EntityDef, EntityField, FieldNameHS(FieldNameHS)
   , PersistEntity(..), PersistValue
   , keyFromValues, fromPersistValues, fieldDB, entityId, entityPrimary
   , entityFields, entityKeyFields, fieldHaskell, compositeFields, persistFieldDef
-  , keyAndEntityFields, toPersistValue, DBName, Update(..), PersistUpdate(..)
+  , keyAndEntityFields, toPersistValue, FieldNameDB, Update(..), PersistUpdate(..)
   , FieldDef(..)
   )
-import Database.Persist.Sql.Types (Sql, SqlBackend, connEscapeName)
 
+import Database.Persist.Sql.Types (Sql, SqlBackend, connEscapeFieldName)
+
 entityColumnNames :: EntityDef -> SqlBackend -> [Sql]
 entityColumnNames ent conn =
      (if hasCompositeKey ent
-      then [] else [connEscapeName conn $ fieldDB (entityId ent)])
-  <> map (connEscapeName conn . fieldDB) (entityFields ent)
+      then [] else [connEscapeFieldName conn . fieldDB $ entityId ent])
+  <> map (connEscapeFieldName conn . fieldDB) (entityFields ent)
 
 keyAndEntityColumnNames :: EntityDef -> SqlBackend -> [Sql]
-keyAndEntityColumnNames ent conn = map (connEscapeName conn . fieldDB) (keyAndEntityFields ent)
+keyAndEntityColumnNames ent conn = map (connEscapeFieldName conn . fieldDB) (keyAndEntityFields ent)
 
 entityColumnCount :: EntityDef -> Int
 entityColumnCount e = length (entityFields e)
@@ -144,18 +145,18 @@
             False
 
 dbIdColumns :: SqlBackend -> EntityDef -> [Text]
-dbIdColumns conn = dbIdColumnsEsc (connEscapeName conn)
+dbIdColumns conn = dbIdColumnsEsc (connEscapeFieldName conn)
 
-dbIdColumnsEsc :: (DBName -> Text) -> EntityDef -> [Text]
+dbIdColumnsEsc :: (FieldNameDB -> Text) -> EntityDef -> [Text]
 dbIdColumnsEsc esc t = map (esc . fieldDB) $ entityKeyFields t
 
 dbColumns :: SqlBackend -> EntityDef -> [Text]
 dbColumns conn t = case entityPrimary t of
     Just _  -> flds
-    Nothing -> escapeDB (entityId t) : flds
+    Nothing -> escapeColumn (entityId t) : flds
   where
-    escapeDB = connEscapeName conn . fieldDB
-    flds = map escapeDB (entityFields t)
+    escapeColumn = connEscapeFieldName conn . fieldDB
+    flds = map escapeColumn (entityFields t)
 
 parseEntityValues :: PersistEntity record
                   => EntityDef -> [PersistValue] -> Either Text (Entity record)
@@ -188,7 +189,7 @@
 
 
 isIdField :: PersistEntity record => EntityField record typ -> Bool
-isIdField f = fieldHaskell (persistFieldDef f) == HaskellName "Id"
+isIdField f = fieldHaskell (persistFieldDef f) == FieldNameHS "Id"
 
 -- | Gets the 'FieldDef' for an 'Update'.
 updateFieldDef :: PersistEntity v => Update v -> FieldDef
@@ -204,9 +205,9 @@
 commaSeparated = T.intercalate ", "
 
 mkUpdateText :: PersistEntity record => SqlBackend -> Update record -> Text
-mkUpdateText conn = mkUpdateText' (connEscapeName conn) id
+mkUpdateText conn = mkUpdateText' (connEscapeFieldName conn) id
 
-mkUpdateText' :: PersistEntity record => (DBName -> Text) -> (Text -> Text) -> Update record -> Text
+mkUpdateText' :: PersistEntity record => (FieldNameDB -> Text) -> (Text -> Text) -> Update record -> Text
 mkUpdateText' escapeName refColumn x =
   case updateUpdate x of
     Assign -> n <> "=?"
@@ -252,7 +253,7 @@
 -- @since 2.11.0.0
 mkInsertPlaceholders
     :: EntityDef
-    -> (DBName -> Text)
+    -> (FieldNameDB -> Text)
     -- ^ An `escape` function
     -> [(Text, Text)]
 mkInsertPlaceholders ed escape =
diff --git a/Database/Persist/Types/Base.hs b/Database/Persist/Types/Base.hs
--- a/Database/Persist/Types/Base.hs
+++ b/Database/Persist/Types/Base.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE CPP #-}
 {-# LANGUAGE LambdaCase #-}
 {-# OPTIONS_GHC -fno-warn-deprecations #-} -- usage of Error typeclass
 module Database.Persist.Types.Base where
@@ -15,7 +16,11 @@
 import qualified Data.HashMap.Strict as HM
 import Data.Int (Int64)
 import Data.Map (Map)
-import Data.Maybe
+import Data.Maybe ( isNothing )
+#if !MIN_VERSION_base(4,11,0)
+-- This can be removed when GHC < 8.2.2 isn't supported anymore
+import Data.Semigroup ((<>))
+#endif
 import qualified Data.Scientific
 import Data.Text (Text, pack)
 import qualified Data.Text as T
@@ -27,9 +32,7 @@
 import Numeric (showHex, readHex)
 import Web.PathPieces (PathPiece(..))
 import Web.HttpApiData (ToHttpApiData (..), FromHttpApiData (..), parseUrlPieceMaybe, showTextData, readTextData, parseBoundedTextData)
-import Data.Monoid
 
-import Prelude
 
 -- | A 'Checkmark' should be used as a field type whenever a
 -- uniqueness constraint should guarantee that a certain kind of
@@ -109,13 +112,36 @@
                  | ByNullableAttr
                   deriving (Eq, Show)
 
+-- | Convenience operations for working with '-NameDB' types.
+--
+-- @since 2.12.0.0
+class DatabaseName a where
+  escapeWith :: (Text -> str) -> (a -> str)
+
+-- | An 'EntityNameDB' represents the datastore-side name that @persistent@
+-- will use for an entity.
+--
+-- @since 2.12.0.0
+newtype EntityNameDB = EntityNameDB { unEntityNameDB :: Text }
+  deriving (Show, Eq, Read, Ord)
+
+instance DatabaseName EntityNameDB where
+  escapeWith f (EntityNameDB n) = f n
+
+-- | An 'EntityNameHS' represents the Haskell-side name that @persistent@
+-- will use for an entity.
+--
+-- @since 2.12.0.0
+newtype EntityNameHS = EntityNameHS { unEntityNameHS :: Text }
+  deriving (Show, Eq, Read, Ord)
+
 -- | An 'EntityDef' represents the information that @persistent@ knows
 -- about an Entity. It uses this information to generate the Haskell
 -- datatype, the SQL migrations, and other relevant conversions.
 data EntityDef = EntityDef
-    { entityHaskell :: !HaskellName
+    { entityHaskell :: !EntityNameHS
     -- ^ The name of the entity as Haskell understands it.
-    , entityDB      :: !DBName
+    , entityDB      :: !EntityNameDB
     -- ^ The name of the database table corresponding to the entity.
     , entityId      :: !FieldDef
     -- ^ The entity's primary key or identifier.
@@ -146,7 +172,7 @@
 
 entitiesPrimary :: EntityDef -> Maybe [FieldDef]
 entitiesPrimary t = case fieldReference primaryField of
-    CompositeRef c -> Just $ (compositeFields c)
+    CompositeRef c -> Just $ compositeFields c
     ForeignRef _ _ -> Just [primaryField]
     _ -> Nothing
   where
@@ -158,9 +184,8 @@
     _ -> Nothing
 
 entityKeyFields :: EntityDef -> [FieldDef]
-entityKeyFields ent = case entityPrimary ent of
-    Nothing   -> [entityId ent]
-    Just pdef -> compositeFields pdef
+entityKeyFields ent =
+    maybe [entityId ent] compositeFields $ entityPrimary ent
 
 keyAndEntityFields :: EntityDef -> [FieldDef]
 keyAndEntityFields ent =
@@ -171,11 +196,6 @@
 
 type ExtraLine = [Text]
 
-newtype HaskellName = HaskellName { unHaskellName :: Text }
-    deriving (Show, Eq, Read, Ord)
-newtype DBName = DBName { unDBName :: Text }
-    deriving (Show, Eq, Read, Ord)
-
 type Attr = Text
 
 -- | Attributes that may be attached to fields that can affect migrations
@@ -240,17 +260,35 @@
     | FTList FieldType
   deriving (Show, Eq, Read, Ord)
 
--- | A 'FieldDef' represents the information that @persistent@ knows about
+-- | An 'EntityNameDB' represents the datastore-side name that @persistent@
+-- will use for an entity.
+--
+-- @since 2.12.0.0
+newtype FieldNameDB = FieldNameDB { unFieldNameDB :: Text }
+  deriving (Show, Eq, Read, Ord)
+
+-- | @since 2.12.0.0
+instance DatabaseName FieldNameDB where
+  escapeWith f (FieldNameDB n) = f n
+
+-- | A 'FieldNameHS' represents the Haskell-side name that @persistent@
+-- will use for a field.
+--
+-- @since 2.12.0.0
+newtype FieldNameHS = FieldNameHS { unFieldNameHS :: Text }
+  deriving (Show, Eq, Read, Ord)
+
+-- | A 'FieldDef' represents the inormation that @persistent@ knows about
 -- a field of a datatype. This includes information used to parse the field
 -- out of the database and what the field corresponds to.
 data FieldDef = FieldDef
-    { fieldHaskell   :: !HaskellName
+    { fieldHaskell   :: !FieldNameHS
     -- ^ The name of the field. Note that this does not corresponds to the
     -- record labels generated for the particular entity - record labels
     -- are generated with the type name prefixed to the field, so
-    -- a 'FieldDef' that contains a @'HaskellName' "name"@ for a type
+    -- a 'FieldDef' that contains a @'FieldNameHS' "name"@ for a type
     -- @User@ will have a record field @userName@.
-    , fieldDB        :: !DBName
+    , fieldDB        :: !FieldNameDB
     -- ^ The name of the field in the database. For SQL databases, this
     -- corresponds to the column name.
     , fieldType      :: !FieldType
@@ -292,8 +330,8 @@
 -- 2) single field
 -- 3) embedded
 data ReferenceDef = NoReference
-                  | ForeignRef !HaskellName !FieldType
-                    -- ^ A ForeignRef has a late binding to the EntityDef it references via HaskellName and has the Haskell type of the foreign key in the form of FieldType
+                  | ForeignRef !EntityNameHS !FieldType
+                    -- ^ A ForeignRef has a late binding to the EntityDef it references via name and has the Haskell type of the foreign key in the form of FieldType
                   | EmbedRef EmbedEntityDef
                   | CompositeRef CompositeDef
                   | SelfReference
@@ -304,7 +342,7 @@
 -- But it is only used for fieldReference
 -- so it only has data needed for embedding
 data EmbedEntityDef = EmbedEntityDef
-    { embeddedHaskell :: !HaskellName
+    { embeddedHaskell :: !EntityNameHS
     , embeddedFields  :: ![EmbedFieldDef]
     } deriving (Show, Eq, Read, Ord)
 
@@ -312,9 +350,9 @@
 -- But it is only used for embeddedFields
 -- so it only has data needed for embedding
 data EmbedFieldDef = EmbedFieldDef
-    { emFieldDB       :: !DBName
+    { emFieldDB    :: !FieldNameDB
     , emFieldEmbed :: Maybe EmbedEntityDef
-    , emFieldCycle :: Maybe HaskellName
+    , emFieldCycle :: Maybe EntityNameHS
     -- ^ 'emFieldEmbed' can create a cycle (issue #311)
     -- when a cycle is detected, 'emFieldEmbed' will be Nothing
     -- and 'emFieldCycle' will be Just
@@ -340,6 +378,24 @@
                         _ -> Nothing
                     }
 
+-- | A 'ConstraintNameDB' represents the datastore-side name that @persistent@
+-- will use for a constraint.
+--
+-- @since 2.12.0.0
+newtype ConstraintNameDB = ConstraintNameDB { unConstraintNameDB :: Text }
+  deriving (Show, Eq, Read, Ord)
+
+-- | @since 2.12.0.0
+instance DatabaseName ConstraintNameDB where
+  escapeWith f (ConstraintNameDB n) = f n
+
+-- | An 'ConstraintNameHS' represents the Haskell-side name that @persistent@
+-- will use for a constraint.
+--
+-- @since 2.12.0.0
+newtype ConstraintNameHS = ConstraintNameHS { unConstraintNameHS :: Text }
+  deriving (Show, Eq, Read, Ord)
+
 -- Type for storing the Uniqueness constraint in the Schema.
 -- Assume you have the following schema with a uniqueness
 -- constraint:
@@ -349,13 +405,13 @@
 --   UniqueAge age
 --
 -- This will be represented as:
--- UniqueDef (HaskellName (packPTH "UniqueAge"))
--- (DBName (packPTH "unique_age")) [(HaskellName (packPTH "age"), DBName (packPTH "age"))] []
+-- UniqueDef (ConstraintNameHS (packPTH "UniqueAge"))
+-- (ConstraintNameDB (packPTH "unique_age")) [(FieldNameHS (packPTH "age"), FieldNameDB (packPTH "age"))] []
 --
 data UniqueDef = UniqueDef
-    { uniqueHaskell :: !HaskellName
-    , uniqueDBName  :: !DBName
-    , uniqueFields  :: ![(HaskellName, DBName)]
+    { uniqueHaskell :: !ConstraintNameHS
+    , uniqueDBName  :: !ConstraintNameDB
+    , uniqueFields  :: ![(FieldNameHS, FieldNameDB)]
     , uniqueAttrs   :: ![Attr]
     }
     deriving (Show, Eq, Read, Ord)
@@ -368,13 +424,13 @@
 
 -- | Used instead of FieldDef
 -- to generate a smaller amount of code
-type ForeignFieldDef = (HaskellName, DBName)
+type ForeignFieldDef = (FieldNameHS, FieldNameDB)
 
 data ForeignDef = ForeignDef
-    { foreignRefTableHaskell       :: !HaskellName
-    , foreignRefTableDBName        :: !DBName
-    , foreignConstraintNameHaskell :: !HaskellName
-    , foreignConstraintNameDBName  :: !DBName
+    { foreignRefTableHaskell       :: !EntityNameHS
+    , foreignRefTableDBName        :: !EntityNameDB
+    , foreignConstraintNameHaskell :: !ConstraintNameHS
+    , foreignConstraintNameDBName  :: !ConstraintNameDB
     , foreignFieldCascade          :: !FieldCascade
     -- ^ Determine how the field will cascade on updates and deletions.
     --
@@ -588,12 +644,14 @@
             Just ('s', t) -> return $ PersistText t
             Just ('b', t) -> either (\_ -> fail "Invalid base64") (return . PersistByteString)
                            $ B64.decode $ TE.encodeUtf8 t
-            Just ('t', t) -> fmap PersistTimeOfDay $ readMay t
-            Just ('u', t) -> fmap PersistUTCTime $ readMay t
-            Just ('d', t) -> fmap PersistDay $ readMay t
-            Just ('r', t) -> fmap PersistRational $ readMay t
-            Just ('o', t) -> maybe (fail "Invalid base64") (return . PersistObjectId) $
-                              fmap (i2bs (8 * 12) . fst) $ headMay $ readHex $ T.unpack t
+            Just ('t', t) -> PersistTimeOfDay <$> readMay t
+            Just ('u', t) -> PersistUTCTime <$> readMay t
+            Just ('d', t) -> PersistDay <$> readMay t
+            Just ('r', t) -> PersistRational <$> readMay t
+            Just ('o', t) -> maybe
+                (fail "Invalid base64")
+                (return . PersistObjectId . i2bs (8 * 12) . fst)
+                $ headMay $ readHex $ T.unpack t
             Just (c, _) -> fail $ "Unknown prefix: " ++ [c]
       where
         headMay []    = Nothing
@@ -615,12 +673,12 @@
             then PersistInt64 $ floor n
             else PersistDouble $ fromRational $ toRational n
     parseJSON (A.Bool b) = return $ PersistBool b
-    parseJSON A.Null = return $ PersistNull
+    parseJSON A.Null = return PersistNull
     parseJSON (A.Array a) = fmap PersistList (mapM A.parseJSON $ V.toList a)
     parseJSON (A.Object o) =
         fmap PersistMap $ mapM go $ HM.toList o
       where
-        go (k, v) = fmap ((,) k) $ A.parseJSON v
+        go (k, v) = (,) k <$> A.parseJSON v
 
 -- | A SQL data type. Naming attempts to reflect the underlying Haskell
 -- datatypes, eg SqlString instead of SqlVarchar. Different SQL databases may
diff --git a/persistent.cabal b/persistent.cabal
--- a/persistent.cabal
+++ b/persistent.cabal
@@ -1,5 +1,5 @@
 name:            persistent
-version:         2.11.0.4
+version:         2.12.0.0
 license:         MIT
 license-file:    LICENSE
 author:          Michael Snoyman <michael@snoyman.com>
@@ -39,6 +39,7 @@
                    , resourcet                >= 1.1.10
                    , scientific
                    , silently
+                   , template-haskell         >= 2.4
                    , text                     >= 1.2
                    , time                     >= 1.6
                    , transformers             >= 0.5
@@ -79,6 +80,12 @@
                      Database.Persist.Sql.Orphan.PersistQuery
                      Database.Persist.Sql.Orphan.PersistStore
                      Database.Persist.Sql.Orphan.PersistUnique
+
+    -- These modules only make sense for compilers with access to DerivingVia
+    if impl(ghc >= 8.6.1)
+      exposed-modules: Database.Persist.Compatible
+      other-modules: Database.Persist.Compatible.Types
+                     Database.Persist.Compatible.TH
 
     ghc-options:     -Wall
     default-language: Haskell2010
diff --git a/test/main.hs b/test/main.hs
--- a/test/main.hs
+++ b/test/main.hs
@@ -1,15 +1,21 @@
-{-# language RecordWildCards, OverloadedStrings, QuasiQuotes #-}
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE QuasiQuotes #-}
+{-# LANGUAGE RecordWildCards #-}
 
 import Test.Hspec
 import qualified Data.Char as Char
 import qualified Data.Text as T
+import Data.List
 import Data.List.NonEmpty (NonEmpty(..))
 import qualified Data.List.NonEmpty as NEL
 import qualified Data.Map as Map
+#if !MIN_VERSION_base(4,11,0)
+-- This can be removed when GHC < 8.2.2 isn't supported anymore
+import Data.Semigroup ((<>))
+#endif
 import Data.Time
 import Text.Shakespeare.Text
-import Data.List
-import Data.Monoid
 
 import Database.Persist.Class.PersistField
 import Database.Persist.Quasi
@@ -71,8 +77,8 @@
             subject ["asdf", "Int"]
                 `shouldBe`
                     Just FieldDef
-                        { fieldHaskell = HaskellName "asdf"
-                        , fieldDB = DBName "asdf"
+                        { fieldHaskell = FieldNameHS "asdf"
+                        , fieldDB = FieldNameDB "asdf"
                         , fieldType = FTTypeCon Nothing "Int"
                         , fieldSqlType = SqlOther "SqlType unset for asdf"
                         , fieldAttrs = []
@@ -86,8 +92,8 @@
             subject ["asdf", "Int", "OnDeleteCascade", "OnUpdateCascade"]
                 `shouldBe`
                     Just FieldDef
-                        { fieldHaskell = HaskellName "asdf"
-                        , fieldDB = DBName "asdf"
+                        { fieldHaskell = FieldNameHS "asdf"
+                        , fieldDB = FieldNameDB "asdf"
                         , fieldType = FTTypeCon Nothing "Int"
                         , fieldSqlType = SqlOther "SqlType unset for asdf"
                         , fieldAttrs = []
@@ -101,8 +107,8 @@
             subject ["asdf", "UserId", "OnDeleteCascade"]
                 `shouldBe`
                     Just FieldDef
-                        { fieldHaskell = HaskellName "asdf"
-                        , fieldDB = DBName "asdf"
+                        { fieldHaskell = FieldNameHS "asdf"
+                        , fieldDB = FieldNameDB "asdf"
                         , fieldType = FTTypeCon Nothing "UserId"
                         , fieldSqlType = SqlOther "SqlType unset for asdf"
                         , fieldAttrs = []
@@ -331,14 +337,15 @@
                     case (name'fieldCount, xs) of
                         ([], []) ->
                             pure ()
-                        (((name, fieldCount) :_), []) ->
+                        ((name, fieldCount) : _, []) ->
                             expectationFailure
                                 $ "Expected an entity with name "
                                 <> name
                                 <> " and " <> show fieldCount <> " fields"
                                 <> ", but the list was empty..."
+
                         ((name, fieldCount) : ys, (EntityDef {..} : xs)) -> do
-                            (unHaskellName entityHaskell, length entityFields)
+                            (unEntityNameHS entityHaskell, length entityFields)
                                 `shouldBe`
                                     (T.pack name, fieldCount)
                             test ys xs
@@ -659,13 +666,13 @@
                     ]
         let [subject] = parse lowerCaseSettings lines
         it "produces the right name" $ do
-            entityHaskell subject `shouldBe` HaskellName "Foo"
+            entityHaskell subject `shouldBe` EntityNameHS "Foo"
         describe "entityFields" $ do
             let fields = entityFields subject
             it "has the right field names" $ do
                 map fieldHaskell fields `shouldMatchList`
-                    [ HaskellName "name"
-                    , HaskellName "age"
+                    [ FieldNameHS "name"
+                    , FieldNameHS "age"
                     ]
             it "has comments" $ do
                 map fieldComments fields `shouldBe`
@@ -715,18 +722,18 @@
                 it "has no extra blocks" $ do
                     entityExtra `shouldBe` mempty
                 it "has the right name" $ do
-                    entityHaskell `shouldBe` HaskellName "IdTable"
+                    entityHaskell `shouldBe` EntityNameHS "IdTable"
                 it "has the right fields" $ do
                     map fieldHaskell entityFields `shouldMatchList`
-                        [ HaskellName "name"
+                        [ FieldNameHS "name"
                         ]
             describe "lowerCaseTable" $ do
                 let EntityDef {..} = lowerCaseTable
                 it "has the right name" $ do
-                    entityHaskell `shouldBe` HaskellName "LowerCaseTable"
+                    entityHaskell `shouldBe` EntityNameHS "LowerCaseTable"
                 it "has the right fields" $ do
                     map fieldHaskell entityFields `shouldMatchList`
-                        [ HaskellName "fullName"
+                        [ FieldNameHS "fullName"
                         ]
                 it "has ExtraBlock" $ do
                     Map.lookup "ExtraBlock" entityExtra
