diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index c019b7230bfb3f394e90be23b91731b0c6402313..7c4f53cab9adb5287c6a890d026d487c512a7ec2 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -815,6 +815,12 @@ vac_truncate_clog(TransactionId frozenXID)
 	/*
 	 * Scan pg_database to compute the minimum datfrozenxid
 	 *
+	 * Since vac_update_datfrozenxid updates datfrozenxid in-place,
+	 * the values could change while we look at them.  Fetch each one just
+	 * once to ensure sane behavior of the comparison logic.  (Here, as in
+	 * many other places, we assume that fetching or updating an XID in shared
+	 * storage is atomic.)
+	 *
 	 * Note: we need not worry about a race condition with new entries being
 	 * inserted by CREATE DATABASE.  Any such entry will have a copy of some
 	 * existing DB's datfrozenxid, and that source DB cannot be ours because
@@ -830,15 +836,16 @@ vac_truncate_clog(TransactionId frozenXID)
 
 	while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
 	{
-		Form_pg_database dbform = (Form_pg_database) GETSTRUCT(tuple);
+		volatile FormData_pg_database *dbform = (Form_pg_database) GETSTRUCT(tuple);
+		TransactionId datfrozenxid = dbform->datfrozenxid;
 
-		Assert(TransactionIdIsNormal(dbform->datfrozenxid));
+		Assert(TransactionIdIsNormal(datfrozenxid));
 
-		if (TransactionIdPrecedes(nextXID, dbform->datfrozenxid))
+		if (TransactionIdPrecedes(nextXID, datfrozenxid))
 			frozenAlreadyWrapped = true;
-		else if (TransactionIdPrecedes(dbform->datfrozenxid, frozenXID))
+		else if (TransactionIdPrecedes(datfrozenxid, frozenXID))
 		{
-			frozenXID = dbform->datfrozenxid;
+			frozenXID = datfrozenxid;
 			oldest_datoid = HeapTupleGetOid(tuple);
 		}
 	}