diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index d088dc1..8b8b97f 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -765,7 +765,7 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex, bool verbose,
 	HeapScanDesc heapScan;
 	bool		use_wal;
 	bool		is_system_catalog;
-	TransactionId OldestXmin;
+	TransactionId OldestXmin = InvalidTransactionId;
 	TransactionId FreezeXid;
 	MultiXactId MultiXactCutoff;
 	RewriteState rwstate;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index d90cb9a..d745127 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -75,7 +75,7 @@ static void vac_truncate_clog(TransactionId frozenXID,
 				  TransactionId lastSaneFrozenXid,
 				  MultiXactId lastSaneMinMulti);
 static bool vacuum_rel(Oid relid, RangeVar *relation, int options,
-		   VacuumParams *params);
+		   VacuumParams *params, TransactionId oldestXmin);
 
 /*
  * Primary entry point for manual VACUUM and ANALYZE commands
@@ -337,7 +337,8 @@ vacuum(int options, List *relations, VacuumParams *params,
 
 			if (options & VACOPT_VACUUM)
 			{
-				if (!vacuum_rel(vrel->oid, vrel->relation, options, params))
+				if (!vacuum_rel(vrel->oid, vrel->relation, options, params,
+								InvalidTransactionId))
 					continue;
 			}
 
@@ -618,8 +619,9 @@ vacuum_set_xid_limits(Relation rel,
 	 * working on a particular table at any time, and that each vacuum is
 	 * always an independent transaction.
 	 */
-	*oldestXmin =
-		TransactionIdLimitedForOldSnapshots(GetOldestXmin(rel, PROCARRAY_FLAGS_VACUUM), rel);
+	if (!TransactionIdIsValid(*oldestXmin))
+		*oldestXmin =
+			TransactionIdLimitedForOldSnapshots(GetOldestXmin(rel, PROCARRAY_FLAGS_VACUUM), rel);
 
 	Assert(TransactionIdIsNormal(*oldestXmin));
 
@@ -1298,7 +1300,8 @@ vac_truncate_clog(TransactionId frozenXID,
  *		At entry and exit, we are not inside a transaction.
  */
 static bool
-vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params)
+vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params,
+		   TransactionId oldestXmin)
 {
 	LOCKMODE	lmode;
 	Relation	onerel;
@@ -1530,6 +1533,19 @@ vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params)
 		toast_relid = InvalidOid;
 
 	/*
+	 * Use same OldestXmin for heap and toast table, otherwise, the heap can
+	 * have RECENTLY_DEAD row that contains toast pointers whose toast rows
+	 * have already been vacuumed away.  This is because OldestXmin can move
+	 * backward on repeated calls. See GetOldestXmin.
+	 */
+	if (OidIsValid(toast_relid))
+	{
+		if (!TransactionIdIsValid(oldestXmin))
+			oldestXmin =
+				TransactionIdLimitedForOldSnapshots(GetOldestXmin(onerel, PROCARRAY_FLAGS_VACUUM), onerel);
+	}
+
+	/*
 	 * Switch to the table owner's userid, so that any index functions are run
 	 * as that user.  Also lock down security-restricted operations and
 	 * arrange to make GUC variable changes local to this command. (This is
@@ -1554,7 +1570,7 @@ vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params)
 					(options & VACOPT_VERBOSE) != 0);
 	}
 	else
-		lazy_vacuum_rel(onerel, options, params, vac_strategy);
+		lazy_vacuum_rel(onerel, options, params, vac_strategy, oldestXmin);
 
 	/* Roll back any GUC changes executed by index functions */
 	AtEOXact_GUC(false, save_nestlevel);
@@ -1580,7 +1596,7 @@ vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params)
 	 * totally unimportant for toast relations.
 	 */
 	if (toast_relid != InvalidOid)
-		vacuum_rel(toast_relid, NULL, options, params);
+		vacuum_rel(toast_relid, NULL, options, params, oldestXmin);
 
 	/*
 	 * Now release the session-level lock on the master table.
diff --git a/src/backend/commands/vacuumlazy.c b/src/backend/commands/vacuumlazy.c
index 5649a70..9331089 100644
--- a/src/backend/commands/vacuumlazy.c
+++ b/src/backend/commands/vacuumlazy.c
@@ -188,7 +188,7 @@ static bool heap_page_is_all_visible(Relation rel, Buffer buf,
  */
 void
 lazy_vacuum_rel(Relation onerel, int options, VacuumParams *params,
-				BufferAccessStrategy bstrategy)
+				BufferAccessStrategy bstrategy, TransactionId oldestXmin)
 {
 	LVRelStats *vacrelstats;
 	Relation   *Irel;
@@ -233,8 +233,9 @@ lazy_vacuum_rel(Relation onerel, int options, VacuumParams *params,
 						  params->freeze_table_age,
 						  params->multixact_freeze_min_age,
 						  params->multixact_freeze_table_age,
-						  &OldestXmin, &FreezeLimit, &xidFullScanLimit,
+						  &oldestXmin, &FreezeLimit, &xidFullScanLimit,
 						  &MultiXactCutoff, &mxactFullScanLimit);
+	OldestXmin = oldestXmin;
 
 	/*
 	 * We request an aggressive scan if the table's frozen Xid is now older
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 85d472f..38a3c60 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -188,7 +188,8 @@ extern void vacuum_delay_point(void);
 
 /* in commands/vacuumlazy.c */
 extern void lazy_vacuum_rel(Relation onerel, int options,
-				VacuumParams *params, BufferAccessStrategy bstrategy);
+				VacuumParams *params, BufferAccessStrategy bstrategy,
+				TransactionId oldestXmin);
 
 /* in commands/analyze.c */
 extern void analyze_rel(Oid relid, RangeVar *relation, int options,
