diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,9 @@
 # Changelog for persistent-sqlite
 
+## 2.10.5
+
+* Foreign keys table constraints are correctly generated [#945](https://github.com/yesodweb/persistent/pull/945) @kderme
+
 ## 2.10.4
 
 * Fix bug with 2.10.3 and 2.10.2 that caused the `RawSqlite` loop. [#934](https://github.com/yesodweb/persistent/pull/934) @merijn
diff --git a/Database/Persist/Sqlite.hs b/Database/Persist/Sqlite.hs
--- a/Database/Persist/Sqlite.hs
+++ b/Database/Persist/Sqlite.hs
@@ -391,8 +391,8 @@
          -> EntityDef
          -> IO (Either [Text] [(Bool, Text)])
 migrate' allDefs getter val = do
-    let (cols, uniqs, _) = mkColumns allDefs val
-    let newSql = mkCreateTable False def (filter (not . safeToRemove val . cName) cols, uniqs)
+    let (cols, uniqs, fdefs) = mkColumns allDefs val
+    let newSql = mkCreateTable False def (filter (not . safeToRemove val . cName) cols, uniqs, fdefs)
     stmt <- getter "SELECT sql FROM sqlite_master WHERE type='table' AND name=?"
     oldSql' <- with (stmtQuery stmt [PersistText $ unDBName table])
       (\src -> runConduit $ src .| go)
@@ -496,10 +496,10 @@
             Just y -> error $ "Invalid result from PRAGMA table_info: " ++ show y
     table = entityDB def
     tableTmp = DBName $ unDBName table <> "_backup"
-    (cols, uniqs, _) = mkColumns allDefs def
+    (cols, uniqs, fdef) = mkColumns allDefs def
     cols' = filter (not . safeToRemove def . cName) cols
-    newSql = mkCreateTable False def (cols', uniqs)
-    tmpSql = mkCreateTable True def { entityDB = tableTmp } (cols', uniqs)
+    newSql = mkCreateTable False def (cols', uniqs, fdef)
+    tmpSql = mkCreateTable True def { entityDB = tableTmp } (cols', uniqs, [])
     dropTmp = "DROP TABLE " <> escape tableTmp
     dropOld = "DROP TABLE " <> escape table
     copyToTemp common = T.concat
@@ -521,8 +521,8 @@
         , escape tableTmp
         ]
 
-mkCreateTable :: Bool -> EntityDef -> ([Column], [UniqueDef]) -> Text
-mkCreateTable isTemp entity (cols, uniqs) =
+mkCreateTable :: Bool -> EntityDef -> ([Column], [UniqueDef], [ForeignDef]) -> Text
+mkCreateTable isTemp entity (cols, uniqs, fdefs) =
   case entityPrimary entity of
     Just pdef ->
        T.concat
@@ -537,6 +537,7 @@
         , T.intercalate "," $ map (escape . fieldDB) $ compositeFields pdef
         , ")"
         , T.concat $ map sqlUnique uniqs
+        , T.concat $ map sqlForeign fdefs
         , ")"
         ]
     Nothing -> T.concat
@@ -552,6 +553,7 @@
         , mayDefault $ defaultAttribute $ fieldAttrs $ entityId entity
         , T.concat $ map (sqlColumn isTemp) cols
         , T.concat $ map sqlUnique uniqs
+        , T.concat $ map sqlForeign fdefs
         , ")"
         ]
 
@@ -571,6 +573,19 @@
     , case ref of
         Nothing -> ""
         Just (table, _) -> if noRef then "" else " REFERENCES " <> escape table
+    ]
+
+sqlForeign :: ForeignDef -> Text
+sqlForeign fdef = T.concat
+    [ ", CONSTRAINT "
+    , escape $ foreignConstraintNameDBName fdef
+    , " FOREIGN KEY("
+    , T.intercalate "," $ map (escape . snd. fst) $ foreignFields fdef
+    , ") REFERENCES "
+    , escape $ foreignRefTableDBName fdef
+    , "("
+    , T.intercalate "," $ map (escape . snd . snd) $ foreignFields fdef
+    , ")"
     ]
 
 sqlUnique :: UniqueDef -> Text
diff --git a/persistent-sqlite.cabal b/persistent-sqlite.cabal
--- a/persistent-sqlite.cabal
+++ b/persistent-sqlite.cabal
@@ -1,5 +1,5 @@
 name:            persistent-sqlite
-version:         2.10.4
+version:         2.10.5
 license:         MIT
 license-file:    LICENSE
 author:          Michael Snoyman <michael@snoyman.com>
