diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,9 @@
 # Changelog for persistent-postgresql
 
+## 2.10.1
+
+* Added support for the `constraint=` attribute to the Postgresql backend. [#979](https://github.com/yesodweb/persistent/pull/979)
+
 ## 2.10.0
 
 * Added question mark operators (`(?.), (?|.), (?&.)`) to `Database.Persist.Postgresql.JSON` [#863](https://github.com/yesodweb/persistent/pull/863)
diff --git a/Database/Persist/Postgresql.hs b/Database/Persist/Postgresql.hs
--- a/Database/Persist/Postgresql.hs
+++ b/Database/Persist/Postgresql.hs
@@ -94,11 +94,12 @@
       "Unexpected PostgreSQL server version, got " <> uniqueMsg
 instance Exception PostgresServerVersionError
 
--- | Create a PostgreSQL connection pool and run the given
--- action.  The pool is properly released after the action
--- finishes using it.  Note that you should not use the given
--- 'ConnectionPool' outside the action since it may already
+-- | Create a PostgreSQL connection pool and run the given action.  The pool is
+-- properly released after the action finishes using it.  Note that you should
+-- not use the given 'ConnectionPool' outside the action since it may already
 -- have been released.
+-- The provided action should use 'runSqlConn' and *not* 'runReaderT' because
+-- the former brackets the database action with transaction begin/commit.
 withPostgresqlPool :: (MonadLogger m, MonadUnliftIO m)
                    => ConnectionString
                    -- ^ Connection string to the database.
@@ -175,6 +176,8 @@
 
 -- | Same as 'withPostgresqlPool', but instead of opening a pool
 -- of connections, only one connection is opened.
+-- The provided action should use 'runSqlConn' and *not* 'runReaderT' because
+-- the former brackets the database action with transaction begin/commit.
 withPostgresqlConn :: (MonadUnliftIO m, MonadLogger m)
                    => ConnectionString -> (SqlBackend -> m a) -> m a
 withPostgresqlConn = withPostgresqlConnWithVersion getServerVersion
@@ -565,7 +568,7 @@
     migrationText exists old'' =
         if not exists
             then createText newcols fdefs udspair
-            else let (acs, ats) = getAlters allDefs entity (newcols, udspair) old'
+            else let (acs, ats) = getAlters allDefs entity (newcols, udspair) $ excludeForeignKeys $ old'
                      acs' = map (AlterColumn name) acs
                      ats' = map (AlterTable name) ats
                  in  acs' ++ ats'
@@ -574,6 +577,13 @@
          (newcols', udefs, fdefs) = mkColumns allDefs entity
          newcols = filter (not . safeToRemove entity . cName) newcols'
          udspair = map udToPair udefs
+         excludeForeignKeys (xs,ys) = (map excludeForeignKey xs,ys)
+         excludeForeignKey c = case cReference c of
+           Just (_,fk) ->
+             case find (\f -> fk == foreignConstraintNameDBName f) fdefs of
+               Just _ -> c { cReference = Nothing }
+               Nothing -> c
+           Nothing -> c
             -- Check for table existence if there are no columns, workaround
             -- for https://github.com/yesodweb/persistent/issues/152
 
@@ -789,23 +799,27 @@
                 Nothing -> loop' ps
                 Just t' -> t'
     getRef cname = do
-        let sql = T.concat
-                [ "SELECT COUNT(*) FROM "
-                , "information_schema.table_constraints "
-                , "WHERE table_catalog=current_database() "
-                , "AND table_schema=current_schema() "
-                , "AND table_name=? "
-                , "AND constraint_type='FOREIGN KEY' "
-                , "AND constraint_name=?"
-                ]
-        let ref = refName tableName' cname
+        let sql = T.concat ["SELECT DISTINCT "
+                           ,"ccu.table_name, "
+                           ,"tc.constraint_name "
+                           ,"FROM information_schema.constraint_column_usage ccu, "
+                           ,"information_schema.key_column_usage kcu, "
+                           ,"information_schema.table_constraints tc "
+                           ,"WHERE tc.constraint_type='FOREIGN KEY' "
+                           ,"AND kcu.constraint_name=tc.constraint_name "
+                           ,"AND ccu.constraint_name=kcu.constraint_name "
+                           ,"AND kcu.ordinal_position=1 "
+                           ,"AND kcu.table_name=? "
+                           ,"AND kcu.column_name=?"]
         stmt <- getter sql
-        with (stmtQuery stmt
-                     [ PersistText $ unDBName tableName'
-                     , PersistText $ unDBName ref
-                     ]) (\src -> runConduit $ src .| do
-            Just [PersistInt64 i] <- CL.head
-            return $ if i == 0 then Nothing else Just (DBName "", ref))
+        cntrs <- with (stmtQuery stmt [PersistText $ unDBName tableName'
+                                      ,PersistText $ unDBName cname])
+                      (\src -> runConduit $ src .| CL.consume)
+        case cntrs of
+          [] -> return Nothing
+          [[PersistText table, PersistText constraint]] ->
+            return $ Just (DBName table, DBName constraint)
+          _ -> error "Postgresql.getColumn: error fetching constraints"
     d' = case defaultValue of
             PersistNull   -> Right Nothing
             PersistText t -> Right $ Just t
@@ -905,7 +919,7 @@
 getAddReference allDefs table reftable cname ref =
     case ref of
         Nothing -> Nothing
-        Just (s, _) -> Just $ AlterColumn table (s, AddReference (refName table cname) [cname] id_)
+        Just (s, constraintName) -> Just $ AlterColumn table (s, AddReference constraintName [cname] id_)
                           where
                             id_ = fromMaybe (error $ "Could not find ID of entity " ++ show reftable)
                                         $ do
@@ -1136,10 +1150,6 @@
         addUser     = maybeAddParam "user"     "PGUSER"
         addPass     = maybeAddParam "password" "PGPASS"
         addDatabase = maybeAddParam "dbname"   "PGDATABASE"
-
-refName :: DBName -> DBName -> DBName
-refName (DBName table) (DBName column) =
-    DBName $ T.concat [table, "_", column, "_fkey"]
 
 udToPair :: UniqueDef -> (DBName, [DBName])
 udToPair ud = (uniqueDBName ud, map snd $ uniqueFields ud)
diff --git a/Database/Persist/Postgresql/JSON.hs b/Database/Persist/Postgresql/JSON.hs
--- a/Database/Persist/Postgresql/JSON.hs
+++ b/Database/Persist/Postgresql/JSON.hs
@@ -199,9 +199,9 @@
 --
 -- @column ?|. list@
 --
--- /N.B. An empty list __will never match anything__. Also, this
--- operator might have some unexpected interactions with
--- non-object values. Please reference the examples./
+-- /N.B. An empty list __will never match anything__. Also, this/
+-- /operator might have some unexpected interactions with/
+-- /non-object values. Please reference the examples./
 --
 -- === __Objects__
 --
@@ -254,9 +254,9 @@
 --
 -- @column ?&. list@
 --
--- /N.B. An empty list __will match anything__. Also, this
--- operator might have some unexpected interactions with
--- non-object values. Please reference the examples./
+-- /N.B. An empty list __will match anything__. Also, this/
+-- /operator might have some unexpected interactions with/
+-- /non-object values. Please reference the examples./
 --
 -- === __Objects__
 --
diff --git a/persistent-postgresql.cabal b/persistent-postgresql.cabal
--- a/persistent-postgresql.cabal
+++ b/persistent-postgresql.cabal
@@ -1,5 +1,5 @@
 name:            persistent-postgresql
-version:         2.10.0
+version:         2.10.1
 license:         MIT
 license-file:    LICENSE
 author:          Felipe Lessa, Michael Snoyman <michael@snoyman.com>
@@ -48,6 +48,7 @@
                      ArrayAggTest
                      EquivalentTypeTestPostgres
                      JSONTest
+                     CustomConstraintTest
     ghc-options:     -Wall
 
     build-depends:   base                 >= 4.9 && < 5
diff --git a/test/CustomConstraintTest.hs b/test/CustomConstraintTest.hs
new file mode 100644
--- /dev/null
+++ b/test/CustomConstraintTest.hs
@@ -0,0 +1,51 @@
+{-# LANGUAGE EmptyDataDecls             #-}
+{-# LANGUAGE FlexibleContexts           #-}
+{-# LANGUAGE GADTs                      #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE MultiParamTypeClasses      #-}
+{-# LANGUAGE OverloadedStrings          #-}
+{-# LANGUAGE QuasiQuotes                #-}
+{-# LANGUAGE TemplateHaskell            #-}
+{-# LANGUAGE TypeFamilies               #-}
+{-# LANGUAGE UndecidableInstances       #-}
+module CustomConstraintTest where
+
+import PgInit
+import qualified Data.Text as T
+
+share [mkPersist sqlSettings, mkMigrate "customConstraintMigrate"] [persistLowerCase|
+CustomConstraint1
+    some_field Text
+    deriving Show
+
+CustomConstraint2
+    cc_id CustomConstraint1Id constraint=custom_constraint
+    deriving Show
+|]
+
+specs :: (MonadIO m, MonadFail m) => RunDb SqlBackend m -> Spec
+specs runDb = do
+  describe "custom constraint used in migration" $ do
+    it "custom constraint is actually created" $ runDb $ do
+      runMigration customConstraintMigrate
+      runMigration customConstraintMigrate -- run a second time to ensure the constraint isn't dropped
+      let query = T.concat ["SELECT DISTINCT COUNT(*) "
+                           ,"FROM information_schema.constraint_column_usage ccu, "
+                           ,"information_schema.key_column_usage kcu, "
+                           ,"information_schema.table_constraints tc "
+                           ,"WHERE tc.constraint_type='FOREIGN KEY' "
+                           ,"AND kcu.constraint_name=tc.constraint_name "
+                           ,"AND ccu.constraint_name=kcu.constraint_name "
+                           ,"AND kcu.ordinal_position=1 "
+                           ,"AND ccu.table_name=? "
+                           ,"AND ccu.column_name=? "
+                           ,"AND kcu.table_name=? "
+                           ,"AND kcu.column_name=? "
+                           ,"AND tc.constraint_name=?"]
+      [Single exists] <- rawSql query [PersistText "custom_constraint1"
+                                      ,PersistText "id"
+                                      ,PersistText "custom_constraint2"
+                                      ,PersistText "cc_id"
+                                      ,PersistText "custom_constraint"]
+      liftIO $ 1 @?= (exists :: Int)
+
diff --git a/test/main.hs b/test/main.hs
--- a/test/main.hs
+++ b/test/main.hs
@@ -46,6 +46,7 @@
 import qualified TreeTest
 import qualified UniqueTest
 import qualified UpsertTest
+import qualified CustomConstraintTest
 
 type Tuple = (,)
 
@@ -172,5 +173,6 @@
     EquivalentTypeTestPostgres.specs
     TransactionLevelTest.specsWith db
     JSONTest.specs
+    CustomConstraintTest.specs db
     -- FIXME: not used, probably should?
     -- ArrayAggTest.specs db
