diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 7c457a6..c5b9959 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -2941,6 +2941,7 @@ TruncateMultiXact(void)
 	mxtruncinfo trunc;
 	MultiXactId earliest;
 	MembersLiveRange range;
+	int offsetsCutoffPage;
 
 	Assert(AmCheckpointerProcess() || AmStartupProcess() ||
 		   !IsPostmasterEnvironment);
@@ -3013,10 +3014,21 @@ TruncateMultiXact(void)
 
 	SlruScanDirectory(MultiXactMemberCtl, SlruScanDirCbRemoveMembers, &range);
 
-	/* Now we can truncate MultiXactOffset */
-	SimpleLruTruncate(MultiXactOffsetCtl,
-					  MultiXactIdToOffsetPage(oldestMXact));
+	/*
+	 * Figure out the cutoff page for offsets.  If there are no multixacts, then
+	 * oldestMXact refers to a multixact that doesn't exist yet, so we will use
+	 * the page for the preceding multixact (which is different only when
+	 * oldestMXact falls in the first entry of a new page).  If we didn't do this,
+	 * we'd be passing SimpleSlruTruncate a cutoff page which doesn't exist yet,
+	 * triggering its wraparound defenses.
+	 */
+	if (oldestMXact == nextMXact)
+		offsetsCutoffPage = MultiXactIdToOffsetPage(oldestMXact - 1);
+	else
+		offsetsCutoffPage = MultiXactIdToOffsetPage(oldestMXact);
 
+	/* Now we can truncate MultiXactOffset */
+	SimpleLruTruncate(MultiXactOffsetCtl, offsetsCutoffPage);
 
 	/*
 	 * Now, and only now, we can advance the stop point for multixact members.
