diff --git a/mysql-test/suite/innodb/t/lock_move_wait_lock_race.test b/mysql-test/suite/innodb/t/lock_move_wait_lock_race.test
new file mode 100644
index 00000000000..3a04c7127c8
--- /dev/null
+++ b/mysql-test/suite/innodb/t/lock_move_wait_lock_race.test
@@ -0,0 +1,58 @@
+--source include/have_innodb.inc
+--source include/count_sessions.inc
+--source include/have_debug.inc
+--source include/have_debug_sync.inc
+
+CREATE TABLE t (pk int PRIMARY KEY, c varchar(10)) ENGINE=InnoDB;
+INSERT INTO t VALUES (10, "0123456789");
+
+--connection default
+BEGIN;
+SELECT * FROM t WHERE c = 10 FOR UPDATE;
+
+--connect(trx2, localhost,root,,)
+BEGIN;
+SET DEBUG_SYNC="lock_wait_start SIGNAL trx2_start_waiting";
+SET DEBUG_SYNC="lock_wait_end SIGNAL trx2_wait_end WAIT_FOR trx2_cont_upd";
+SET DEBUG_SYNC="lock_rec_store_on_page_infimum_end SIGNAL trx2_moved_locks WAIT_FOR trx2_cont";
+#################
+# We need to update clustered record without changing ordering fields and
+# changing the size of non-ordering fields to cause locks moving from deleted
+# record to infimum.
+###
+--send UPDATE t SET c = NULL WHERE pk = 10
+
+
+--connect(trx3, localhost,root,,)
+SET DEBUG_SYNC="now WAIT_FOR trx2_start_waiting";
+#################
+# The condition wariable waiting in lock_wait() must be finished by timeout
+###
+SET innodb_lock_wait_timeout=1;
+BEGIN;
+SET DEBUG_SYNC="lock_wait_start SIGNAL trx3_start_waiting WAIT_FOR trx3_cont_waiting";
+SET DEBUG_SYNC="lock_sys_t_cancel_enter SIGNAL trx3_cancel_enter WAIT_FOR trx3_cont_cancel_waiting";
+--send UPDATE t SET c = "abcdefghij" WHERE pk = 10
+
+--connection default
+SET DEBUG_SYNC="now WAIT_FOR trx3_start_waiting";
+COMMIT;
+SET DEBUG_SYNC="now WAIT_FOR trx2_wait_end";
+SET DEBUG_SYNC="now SIGNAL trx3_cont_waiting";
+SET DEBUG_SYNC="now WAIT_FOR trx3_cancel_enter";
+SET DEBUG_SYNC="now SIGNAL trx2_cont_upd";
+SET DEBUG_SYNC="now WAIT_FOR trx2_moved_locks";
+#################
+# If the bug is not fixed, there will be assertion failure here, because trx2
+# moved trx3 lock from deleted record to infimum when trx3 tried to cancel the
+# lock.
+###
+SET DEBUG_SYNC="now SIGNAL trx3_cont_cancel_waiting";
+SET DEBUG_SYNC="now SIGNAL trx2_cont";
+
+--disconnect trx2
+--disconnect trx3
+--connection default
+SET DEBUG_SYNC="RESET";
+DROP TABLE t;
+--source include/wait_until_count_sessions.inc
diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc
index db4035157b0..5d1166bf4bb 100644
--- a/storage/innobase/lock/lock0lock.cc
+++ b/storage/innobase/lock/lock0lock.cc
@@ -3178,6 +3178,8 @@ lock_rec_store_on_page_infimum(
 
   ut_ad(block->page.frame == page_align(rec));
   const page_id_t id{block->page.id()};
+  ut_d(SCOPE_EXIT(
+      []() { DEBUG_SYNC_C("lock_rec_store_on_page_infimum_end"); }));
 
   LockGuard g{lock_sys.rec_hash, id};
   lock_rec_move(g.cell(), *block, id, g.cell(), id,
@@ -5763,6 +5765,7 @@ void lock_sys_t::cancel_lock_wait_for_trx(trx_t *trx)
 template<bool check_victim>
 dberr_t lock_sys_t::cancel(trx_t *trx, lock_t *lock)
 {
+  DEBUG_SYNC_C("lock_sys_t_cancel_enter");
   mysql_mutex_assert_owner(&lock_sys.wait_mutex);
   ut_ad(trx->lock.wait_lock == lock);
   ut_ad(trx->state == TRX_STATE_ACTIVE);
