Page        page;
    BlockNumber block;
    Buffer      buffer;
+   TransactionId prune_xid;
 
    Assert(ItemPointerIsValid(tid));
 
    START_CRIT_SECTION();
 
    /*
-    * The tuple will become DEAD immediately.  Flag that this page
-    * immediately is a candidate for pruning by setting xmin to
-    * RecentGlobalXmin.  That's not pretty, but it doesn't seem worth
-    * inventing a nicer API for this.
+    * The tuple will become DEAD immediately.  Flag that this page is a
+    * candidate for pruning by setting xmin to TransactionXmin. While not
+    * immediately prunable, it is the oldest xid we can cheaply determine
+    * that's safe against wraparound / being older than the table's
+    * relfrozenxid.  To defend against the unlikely case of a new relation
+    * having a newer relfrozenxid than our TransactionXmin, use relfrozenxid
+    * if so (vacuum can't subsequently move relfrozenxid to beyond
+    * TransactionXmin, so there's no race here).
     */
-   Assert(TransactionIdIsValid(RecentGlobalXmin));
-   PageSetPrunable(page, RecentGlobalXmin);
+   Assert(TransactionIdIsValid(TransactionXmin));
+   if (TransactionIdPrecedes(TransactionXmin, relation->rd_rel->relfrozenxid))
+       prune_xid = relation->rd_rel->relfrozenxid;
+   else
+       prune_xid = TransactionXmin;
+   PageSetPrunable(page, prune_xid);
 
    /* store transaction information of xact deleting the tuple */
    tp.t_data->t_infomask &= ~(HEAP_XMAX_BITS | HEAP_MOVED);