diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 8d596202ba4c2270ae1b897aa97b6894d39bb8bf..2035a2158f1aab6c6e01885b270d7dac080fc86c 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -4859,10 +4859,23 @@ test_lockmode_for_conflict(MultiXactStatus status, TransactionId xid,
 	else if (TransactionIdDidCommit(xid))
 	{
 		/*
-		 * If the updating transaction committed, what we do depends on whether
-		 * the lock modes conflict: if they do, then we must report error to
-		 * caller.  But if they don't, we can fall through to lock it.
+		 * The other transaction committed.  If it was only a locker, then the
+		 * lock is completely gone now and we can return success; but if it
+		 * was an update, then what we do depends on whether the two lock
+		 * modes conflict.	If they conflict, then we must report error to
+		 * caller. But if they don't, we can fall through to allow the current
+		 * transaction to lock the tuple.
+		 *
+		 * Note: the reason we worry about ISUPDATE here is because as soon as
+		 * a transaction ends, all its locks are gone and meaningless, and
+		 * thus we can ignore them; whereas its updates persist.  In the
+		 * TransactionIdIsInProgress case, above, we don't need to check
+		 * because we know the lock is still "alive" and thus a conflict needs
+		 * always be checked.
 		 */
+		if (!ISUPDATE_from_mxstatus(status))
+			return HeapTupleMayBeUpdated;
+
 		if (DoLockModesConflict(LOCKMODE_from_mxstatus(status),
 								LOCKMODE_from_mxstatus(wantedstatus)))
 			/* bummer */
diff --git a/src/test/isolation/expected/multixact-no-forget.out b/src/test/isolation/expected/multixact-no-forget.out
new file mode 100644
index 0000000000000000000000000000000000000000..38466bf837476c1db81d4c8ad5b8ed22f9e371fc
--- /dev/null
+++ b/src/test/isolation/expected/multixact-no-forget.out
@@ -0,0 +1,130 @@
+Parsed test spec with 3 sessions
+
+starting permutation: s1_show s1_commit s2_commit
+step s1_show: SELECT current_setting('default_transaction_isolation') <> 'read committed';
+?column?       
+
+f              
+step s1_commit: COMMIT;
+step s2_commit: COMMIT;
+
+starting permutation: s1_lock s2_update s2_abort s3_forkeyshr s1_commit
+step s1_lock: SELECT * FROM dont_forget FOR KEY SHARE;
+value          
+
+1              
+step s2_update: UPDATE dont_forget SET value = 2;
+step s2_abort: ROLLBACK;
+step s3_forkeyshr: SELECT * FROM dont_forget FOR KEY SHARE;
+value          
+
+1              
+step s1_commit: COMMIT;
+
+starting permutation: s1_lock s2_update s2_commit s3_forkeyshr s1_commit
+step s1_lock: SELECT * FROM dont_forget FOR KEY SHARE;
+value          
+
+1              
+step s2_update: UPDATE dont_forget SET value = 2;
+step s2_commit: COMMIT;
+step s3_forkeyshr: SELECT * FROM dont_forget FOR KEY SHARE;
+value          
+
+2              
+step s1_commit: COMMIT;
+
+starting permutation: s1_lock s2_update s1_commit s3_forkeyshr s2_commit
+step s1_lock: SELECT * FROM dont_forget FOR KEY SHARE;
+value          
+
+1              
+step s2_update: UPDATE dont_forget SET value = 2;
+step s1_commit: COMMIT;
+step s3_forkeyshr: SELECT * FROM dont_forget FOR KEY SHARE;
+value          
+
+1              
+step s2_commit: COMMIT;
+
+starting permutation: s1_lock s2_update s2_abort s3_fornokeyupd s1_commit
+step s1_lock: SELECT * FROM dont_forget FOR KEY SHARE;
+value          
+
+1              
+step s2_update: UPDATE dont_forget SET value = 2;
+step s2_abort: ROLLBACK;
+step s3_fornokeyupd: SELECT * FROM dont_forget FOR NO KEY UPDATE;
+value          
+
+1              
+step s1_commit: COMMIT;
+
+starting permutation: s1_lock s2_update s2_commit s3_fornokeyupd s1_commit
+step s1_lock: SELECT * FROM dont_forget FOR KEY SHARE;
+value          
+
+1              
+step s2_update: UPDATE dont_forget SET value = 2;
+step s2_commit: COMMIT;
+step s3_fornokeyupd: SELECT * FROM dont_forget FOR NO KEY UPDATE;
+value          
+
+2              
+step s1_commit: COMMIT;
+
+starting permutation: s1_lock s2_update s1_commit s3_fornokeyupd s2_commit
+step s1_lock: SELECT * FROM dont_forget FOR KEY SHARE;
+value          
+
+1              
+step s2_update: UPDATE dont_forget SET value = 2;
+step s1_commit: COMMIT;
+step s3_fornokeyupd: SELECT * FROM dont_forget FOR NO KEY UPDATE; <waiting ...>
+step s2_commit: COMMIT;
+step s3_fornokeyupd: <... completed>
+value          
+
+2              
+
+starting permutation: s1_lock s2_update s2_abort s3_forupd s1_commit
+step s1_lock: SELECT * FROM dont_forget FOR KEY SHARE;
+value          
+
+1              
+step s2_update: UPDATE dont_forget SET value = 2;
+step s2_abort: ROLLBACK;
+step s3_forupd: SELECT * FROM dont_forget FOR UPDATE; <waiting ...>
+step s1_commit: COMMIT;
+step s3_forupd: <... completed>
+value          
+
+1              
+
+starting permutation: s1_lock s2_update s2_commit s3_forupd s1_commit
+step s1_lock: SELECT * FROM dont_forget FOR KEY SHARE;
+value          
+
+1              
+step s2_update: UPDATE dont_forget SET value = 2;
+step s2_commit: COMMIT;
+step s3_forupd: SELECT * FROM dont_forget FOR UPDATE; <waiting ...>
+step s1_commit: COMMIT;
+step s3_forupd: <... completed>
+value          
+
+2              
+
+starting permutation: s1_lock s2_update s1_commit s3_forupd s2_commit
+step s1_lock: SELECT * FROM dont_forget FOR KEY SHARE;
+value          
+
+1              
+step s2_update: UPDATE dont_forget SET value = 2;
+step s1_commit: COMMIT;
+step s3_forupd: SELECT * FROM dont_forget FOR UPDATE; <waiting ...>
+step s2_commit: COMMIT;
+step s3_forupd: <... completed>
+value          
+
+2              
diff --git a/src/test/isolation/expected/multixact-no-forget_1.out b/src/test/isolation/expected/multixact-no-forget_1.out
new file mode 100644
index 0000000000000000000000000000000000000000..1c37afef1a2cfec80a2444957a40fa24db4be2e8
--- /dev/null
+++ b/src/test/isolation/expected/multixact-no-forget_1.out
@@ -0,0 +1,126 @@
+Parsed test spec with 3 sessions
+
+starting permutation: s1_show s1_commit s2_commit
+step s1_show: SELECT current_setting('default_transaction_isolation') <> 'read committed';
+?column?       
+
+t              
+step s1_commit: COMMIT;
+step s2_commit: COMMIT;
+
+starting permutation: s1_lock s2_update s2_abort s3_forkeyshr s1_commit
+step s1_lock: SELECT * FROM dont_forget FOR KEY SHARE;
+value          
+
+1              
+step s2_update: UPDATE dont_forget SET value = 2;
+step s2_abort: ROLLBACK;
+step s3_forkeyshr: SELECT * FROM dont_forget FOR KEY SHARE;
+value          
+
+1              
+step s1_commit: COMMIT;
+
+starting permutation: s1_lock s2_update s2_commit s3_forkeyshr s1_commit
+step s1_lock: SELECT * FROM dont_forget FOR KEY SHARE;
+value          
+
+1              
+step s2_update: UPDATE dont_forget SET value = 2;
+step s2_commit: COMMIT;
+step s3_forkeyshr: SELECT * FROM dont_forget FOR KEY SHARE;
+value          
+
+2              
+step s1_commit: COMMIT;
+
+starting permutation: s1_lock s2_update s1_commit s3_forkeyshr s2_commit
+step s1_lock: SELECT * FROM dont_forget FOR KEY SHARE;
+value          
+
+1              
+step s2_update: UPDATE dont_forget SET value = 2;
+step s1_commit: COMMIT;
+step s3_forkeyshr: SELECT * FROM dont_forget FOR KEY SHARE;
+value          
+
+1              
+step s2_commit: COMMIT;
+
+starting permutation: s1_lock s2_update s2_abort s3_fornokeyupd s1_commit
+step s1_lock: SELECT * FROM dont_forget FOR KEY SHARE;
+value          
+
+1              
+step s2_update: UPDATE dont_forget SET value = 2;
+step s2_abort: ROLLBACK;
+step s3_fornokeyupd: SELECT * FROM dont_forget FOR NO KEY UPDATE;
+value          
+
+1              
+step s1_commit: COMMIT;
+
+starting permutation: s1_lock s2_update s2_commit s3_fornokeyupd s1_commit
+step s1_lock: SELECT * FROM dont_forget FOR KEY SHARE;
+value          
+
+1              
+step s2_update: UPDATE dont_forget SET value = 2;
+step s2_commit: COMMIT;
+step s3_fornokeyupd: SELECT * FROM dont_forget FOR NO KEY UPDATE;
+value          
+
+2              
+step s1_commit: COMMIT;
+
+starting permutation: s1_lock s2_update s1_commit s3_fornokeyupd s2_commit
+step s1_lock: SELECT * FROM dont_forget FOR KEY SHARE;
+value          
+
+1              
+step s2_update: UPDATE dont_forget SET value = 2;
+step s1_commit: COMMIT;
+step s3_fornokeyupd: SELECT * FROM dont_forget FOR NO KEY UPDATE; <waiting ...>
+step s2_commit: COMMIT;
+step s3_fornokeyupd: <... completed>
+error in steps s2_commit s3_fornokeyupd: ERROR:  could not serialize access due to concurrent update
+
+starting permutation: s1_lock s2_update s2_abort s3_forupd s1_commit
+step s1_lock: SELECT * FROM dont_forget FOR KEY SHARE;
+value          
+
+1              
+step s2_update: UPDATE dont_forget SET value = 2;
+step s2_abort: ROLLBACK;
+step s3_forupd: SELECT * FROM dont_forget FOR UPDATE; <waiting ...>
+step s1_commit: COMMIT;
+step s3_forupd: <... completed>
+value          
+
+1              
+
+starting permutation: s1_lock s2_update s2_commit s3_forupd s1_commit
+step s1_lock: SELECT * FROM dont_forget FOR KEY SHARE;
+value          
+
+1              
+step s2_update: UPDATE dont_forget SET value = 2;
+step s2_commit: COMMIT;
+step s3_forupd: SELECT * FROM dont_forget FOR UPDATE; <waiting ...>
+step s1_commit: COMMIT;
+step s3_forupd: <... completed>
+value          
+
+2              
+
+starting permutation: s1_lock s2_update s1_commit s3_forupd s2_commit
+step s1_lock: SELECT * FROM dont_forget FOR KEY SHARE;
+value          
+
+1              
+step s2_update: UPDATE dont_forget SET value = 2;
+step s1_commit: COMMIT;
+step s3_forupd: SELECT * FROM dont_forget FOR UPDATE; <waiting ...>
+step s2_commit: COMMIT;
+step s3_forupd: <... completed>
+error in steps s2_commit s3_forupd: ERROR:  could not serialize access due to concurrent update
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index 329dbf12fa5586d2d41109b2bca64d911b5b7d73..dd4b404183674173bca44e76f7086d90787fc164 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -20,5 +20,6 @@ test: delete-abort-savept
 test: delete-abort-savept-2
 test: aborted-keyrevoke
 test: multixact-no-deadlock
+test: multixact-no-forget
 test: drop-index-concurrently-1
 test: timeouts
diff --git a/src/test/isolation/specs/multixact-no-forget.spec b/src/test/isolation/specs/multixact-no-forget.spec
new file mode 100644
index 0000000000000000000000000000000000000000..7fb93c1e3442101849dbf742b86c3d3f8b4492a8
--- /dev/null
+++ b/src/test/isolation/specs/multixact-no-forget.spec
@@ -0,0 +1,44 @@
+# If transaction A holds a lock, and transaction B does an update,
+# make sure we don't forget the lock if B aborts.
+setup
+{
+  CREATE TABLE dont_forget (
+	value	int
+  );
+
+  INSERT INTO dont_forget VALUES (1);
+}
+
+teardown
+{
+  DROP TABLE dont_forget;
+}
+
+session "s1"
+setup			{ BEGIN; }
+step "s1_show"	{ SELECT current_setting('default_transaction_isolation') <> 'read committed'; }
+step "s1_lock"	{ SELECT * FROM dont_forget FOR KEY SHARE; }
+step "s1_commit" { COMMIT; }
+
+session "s2"
+setup				{ BEGIN; }
+step "s2_update"	{ UPDATE dont_forget SET value = 2; }
+step "s2_abort"		{ ROLLBACK; }
+step "s2_commit"	{ COMMIT; }
+
+session "s3"
+# try cases with both a non-conflicting lock with s1's and a conflicting one
+step "s3_forkeyshr"	{ SELECT * FROM dont_forget FOR KEY SHARE; }
+step "s3_fornokeyupd"	{ SELECT * FROM dont_forget FOR NO KEY UPDATE; }
+step "s3_forupd"	{ SELECT * FROM dont_forget FOR UPDATE; }
+
+permutation "s1_show" "s1_commit" "s2_commit"
+permutation "s1_lock" "s2_update" "s2_abort" "s3_forkeyshr" "s1_commit"
+permutation "s1_lock" "s2_update" "s2_commit" "s3_forkeyshr" "s1_commit"
+permutation "s1_lock" "s2_update" "s1_commit" "s3_forkeyshr" "s2_commit"
+permutation "s1_lock" "s2_update" "s2_abort" "s3_fornokeyupd" "s1_commit"
+permutation "s1_lock" "s2_update" "s2_commit" "s3_fornokeyupd" "s1_commit"
+permutation "s1_lock" "s2_update" "s1_commit" "s3_fornokeyupd" "s2_commit"
+permutation "s1_lock" "s2_update" "s2_abort" "s3_forupd" "s1_commit"
+permutation "s1_lock" "s2_update" "s2_commit" "s3_forupd" "s1_commit"
+permutation "s1_lock" "s2_update" "s1_commit" "s3_forupd" "s2_commit"