diff --git a/contrib/pg_upgrade/pg_upgrade.c b/contrib/pg_upgrade/pg_upgrade.c
index cd70b6a..74e5b63 100644
--- a/contrib/pg_upgrade/pg_upgrade.c
+++ b/contrib/pg_upgrade/pg_upgrade.c
@@ -398,6 +398,8 @@ copy_subdir_files(char *subdir)
 static void
 copy_clog_xlog_xid(void)
 {
+	char	multioffdir[MAXPGPATH];
+
 	/* copy old commit logs to new data dir */
 	copy_subdir_files("pg_clog");
 
@@ -410,6 +412,16 @@ copy_clog_xlog_xid(void)
 	check_ok();
 
 	/*
+	 * Remove pg_multixact/offset files before going any further.  initdb
+	 * created file 0000 there, which is problematic for future multixact
+	 * truncation.  Note we remove any other junk in the subdir alongside the
+	 * 0000 file.
+	 */
+	snprintf(multioffdir, sizeof(multioffdir),
+			 "%s/pg_multixact/offsets", new_cluster.pgdata);
+	rmtree(multioffdir, false);
+
+	/*
 	 * If the old server is before the MULTIXACT_FORMATCHANGE_CAT_VER change
 	 * (see pg_upgrade.h) and the new server is after, then we don't copy
 	 * pg_multixact files, but we need to reset pg_control so that the new
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index ccdcb5b..baed722 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -5326,8 +5326,14 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
 		 * was a locker only, it can be removed without any further
 		 * consideration; but if it contained an update, we might need to
 		 * preserve it.
+		 *
+		 * Don't assert MultiXactIdIsRunning if the multi came from a
+		 * pg_upgrade'd share-locked tuple, though, as doing that causes an
+		 * error to be raised unnecessarily.
 		 */
-		Assert(!MultiXactIdIsRunning(multi));
+		Assert((!(t_infomask & HEAP_LOCK_MASK) &&
+				HEAP_XMAX_IS_LOCKED_ONLY(t_infomask)) ||
+			   !MultiXactIdIsRunning(multi));
 		if (HEAP_XMAX_IS_LOCKED_ONLY(t_infomask))
 		{
 			*flags |= FRM_INVALIDATE_XMAX;
