diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,3 +1,11 @@
+# 0.5.6.1
+
+## Bug fixes
+
+* Fixed a critical bug introduced by the performance improvements of 0.5.6.0, which would
+  result in unexpected type errors when executing database queries.
+  While the bug has been fixed, performance remains as good as the 0.5.6.0 release (#803)
+
 # 0.5.6.0
 
 ## Added features
diff --git a/Database/Beam/Postgres/Connection.hs b/Database/Beam/Postgres/Connection.hs
--- a/Database/Beam/Postgres/Connection.hs
+++ b/Database/Beam/Postgres/Connection.hs
@@ -197,16 +197,16 @@
   -- Default batch size is 256 rows, set by 'postgresql-simple'
   -- 'defaultFoldOptions' (FetchQuantity = Automatic, which resolves to
   -- 256 in 'Database.PostgreSQL.Simple').
-  fieldsCache <- newIORef (Nothing :: Maybe (Vector Pg.Field))
+  fieldsCache <- newIORef (Nothing :: Maybe (Pg.Result, Vector Pg.Field))
 
   let cachedGetFields :: Pg.Result -> IO (Vector Pg.Field)
       cachedGetFields res = do
         cached <- readIORef fieldsCache
         case cached of
-          Just fs -> pure fs
+          Just (cachedRes, fs) | cachedRes == res -> pure fs
           _ -> do
             fs <- getFields res
-            writeIORef fieldsCache (Just fs)
+            writeIORef fieldsCache (Just (res, fs))
             pure fs
 
       finish x = pure (Right x)
@@ -258,7 +258,10 @@
                -- Hoist per-query metadata out of the per-row loop: the
                -- same 'Pg.Result' is used for every row, so 'fields'
                -- and 'rowCount' are loop-invariant.
-               fields <- cachedGetFields res
+               -- Use getFields directly: unsafeFreeResult below lets libpq
+               -- reuse the pointer address, which would cause a false hit in
+               -- cachedGetFields on the next query.
+               fields <- getFields res
                Pg.Row rowCount <- Pg.ntuples res
                let Pg process = mkProcess (Pg (liftF (PgFetchNext id)))
                runF process (\x _ -> Pg.unsafeFreeResult res >> next x)
diff --git a/beam-postgres.cabal b/beam-postgres.cabal
--- a/beam-postgres.cabal
+++ b/beam-postgres.cabal
@@ -1,5 +1,5 @@
 name:                 beam-postgres
-version:              0.5.6.0
+version:              0.5.6.1
 synopsis:             Connection layer between beam and postgres
 description:          Beam driver for <https://www.postgresql.org/ PostgreSQL>, an advanced open-source RDBMS
 homepage:             https://haskell-beam.github.io/beam/user-guide/backends/beam-postgres
diff --git a/test/Database/Beam/Postgres/Test/Select.hs b/test/Database/Beam/Postgres/Test/Select.hs
--- a/test/Database/Beam/Postgres/Test/Select.hs
+++ b/test/Database/Beam/Postgres/Test/Select.hs
@@ -1,4 +1,5 @@
 {-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE StandaloneDeriving #-}
 
 module Database.Beam.Postgres.Test.Select (tests) where
 
@@ -12,6 +13,7 @@
 import           Test.Tasty.HUnit
 import           Data.UUID (UUID, nil)
 import qualified Data.UUID.V5 as V5
+import           Database.PostgreSQL.Simple (execute_)
 
 import           Database.Beam
 import           Database.Beam.Backend.SQL.SQL92
@@ -58,6 +60,7 @@
   , testInSelect getConn
   , testReturningMany getConn
   , testPgUnnest getConn
+  , testFieldsCacheStale getConn
   ]
 
 testPgArrayToJSON :: IO ByteString -> TestTree
@@ -205,6 +208,53 @@
     SqlSelect Postgres x -> (Pg (Maybe x) -> Pg a) -> Pg a
   runSelectReturningMany (SqlSelect s) =
     runReturningMany (selectCmd s)
+
+-- Tables for fieldsCache regression test (PR #797).
+-- AlphaT has a Text column; BetaT has an Int32 column.
+-- Querying both within a single runBeamPostgres call exposes the
+-- stale-cache bug: the second query gets field OID metadata from the
+-- first (text OID 25 instead of int4 OID 23), causing a type mismatch.
+
+data AlphaT f = Alpha { alphaName :: C f T.Text } deriving (Generic, Beamable)
+
+instance Table AlphaT where
+  data PrimaryKey AlphaT f = AlphaPk (C f T.Text) deriving (Generic, Beamable)
+  primaryKey = AlphaPk . alphaName
+
+data BetaT f = Beta { betaValue :: C f Int32 } deriving (Generic, Beamable)
+
+instance Table BetaT where
+  data PrimaryKey BetaT f = BetaPk (C f Int32) deriving (Generic, Beamable)
+  primaryKey = BetaPk . betaValue
+
+data FieldsCacheDb e = FieldsCacheDb
+  { dbAlpha :: e (TableEntity AlphaT)
+  , dbBeta  :: e (TableEntity BetaT)
+  } deriving (Generic, Database Postgres)
+
+fieldsCacheDb :: DatabaseSettings Postgres FieldsCacheDb
+fieldsCacheDb = defaultDbSettings
+
+-- | Regression test for the fieldsCache bug introduced in PR #797.
+-- withPgDebug keeps a per-invocation IORef (Maybe (Vector Field)).
+-- The cache hit arm (Just fs -> pure fs) never validates against the
+-- current Pg.Result, so the second SELECT in one runBeamPostgres call
+-- inherits stale OID metadata from the first, producing a type-mismatch
+-- error when the two queries return different column types.
+testFieldsCacheStale :: IO ByteString -> TestTree
+testFieldsCacheStale getConn =
+  testCase "fieldsCache is not reused across queries with different schemas" $
+  withTestPostgres "fields_cache_stale" getConn $ \conn -> do
+    execute_ conn "CREATE TABLE alpha (name TEXT NOT NULL)"
+    execute_ conn "CREATE TABLE beta  (value INT4 NOT NULL)"
+    execute_ conn "INSERT INTO alpha VALUES ('hello')"
+    execute_ conn "INSERT INTO beta  VALUES (42)"
+    (names, values) <- runBeamPostgres conn $ do
+      ns <- runSelectReturningList $ select $ all_ (dbAlpha fieldsCacheDb)
+      vs <- runSelectReturningList $ select $ all_ (dbBeta  fieldsCacheDb)
+      pure (ns, vs)
+    assertEqual "alpha rows" ["hello" :: T.Text] (alphaName <$> names)
+    assertEqual "beta rows"  [42 :: Int32]       (betaValue <$> values)
 
 testFunction :: IO ByteString -> String -> (Connection -> Assertion) -> TestTree
 testFunction getConn name mkAssertion = testCase name $
