※この記事にはアフィリエイト広告(プロモーション)が含まれます。
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction は、InnoDB の行ロックを innodb_lock_wait_timeout(既定 50 秒)待っても取れなかったときのエラーです。この記事の出力は MySQL 8.4.11(Ubuntu 26.04)で採りました。
まず見る(結論)
SELECT waiting_pid, waiting_query, blocking_pid, blocking_query,
blocking_trx_age, sql_kill_blocking_connection
FROM sys.innodb_lock_waits;
blocking_queryがNULLなら、止めている側はコミットせずに放置されている。KILL QUERYでは外れず、KILL <blocking_pid>で接続ごと切る- 1205 で取り消されるのはその文だけ。トランザクションは続いているので、アプリ側で
ROLLBACKする
止めている接続を探す
待たされている間に sys.innodb_lock_waits を引くと、待っている側と止めている側が1行で出ます(抜粋)。
mysql> SELECT * FROM sys.innodb_lock_waits\G
*************************** 1. row ***************************
wait_started: 2026-11-10 14:46:43
wait_age_secs: 2
locked_table: `fsv`.`acct`
locked_index: PRIMARY
waiting_pid: 13
waiting_query: UPDATE acct SET bal=bal+10 WHERE id=1
waiting_lock_mode: X,REC_NOT_GAP
blocking_pid: 11
blocking_query: DO SLEEP(30)
blocking_trx_started: 2026-11-10 14:46:38
blocking_trx_age: 00:00:07
sql_kill_blocking_query: KILL QUERY 11
sql_kill_blocking_connection: KILL 11
blocking_pid は SHOW PROCESSLIST の Id と同じ番号です。行ロックの中身まで見るなら performance_schema.data_locks を使います。LOCK_STATUS が WAITING の行が待っている側で、LOCK_DATA が対象の主キーの値(ここでは 1)です。
Sleep のまま握っている接続
BEGIN → UPDATE のあとコミットせずに止まった接続は、SHOW PROCESSLIST では Command が Sleep、Info が NULL です。何もしていないように見えますが、ロックは持ったままです。
mysql> SELECT trx_mysql_thread_id, trx_state, trx_started, trx_query FROM information_schema.innodb_trx;
+---------------------+-----------+---------------------+----------------------------------+
| trx_mysql_thread_id | trx_state | trx_started | trx_query |
+---------------------+-----------+---------------------+----------------------------------+
| 33 | LOCK WAIT | 2026-11-10 14:47:46 | UPDATE acct SET bal=1 WHERE id=3 |
| 32 | RUNNING | 2026-11-10 14:47:44 | NULL |
+---------------------+-----------+---------------------+----------------------------------+
trx_query が NULL で trx_started の古い行が、放置された接続です。
| 止めている側(32)に実行 | ロック |
|---|---|
KILL QUERY 32 |
外れない。sys.innodb_lock_waits に同じ行が残る |
KILL 32 |
外れる。32 の UPDATE はロールバックされ、33 の UPDATE が通った |
KILL QUERY は実行中の文を止めるだけで、文を実行していない接続には効きません。接続を切るには sys.innodb_lock_waits の sql_kill_blocking_connection 列の文を使います。
1205 のあともトランザクションは続く
同じトランザクションの中で INSERT したあと UPDATE が 1205 になり、そのまま次の INSERT と COMMIT を実行しました。
BEGIN;
INSERT INTO log1(msg) VALUES ('before');
UPDATE acct SET bal=bal+10 WHERE id=2;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
SELECT trx_state FROM information_schema.innodb_trx WHERE trx_mysql_thread_id = CONNECTION_ID();
-- RUNNING
INSERT INTO log1(msg) VALUES ('after');
COMMIT;
COMMIT 後の log1 には before と after の2行が入り、UPDATE だけが反映されていませんでした。innodb_rollback_on_timeout が既定の OFF だと、1205 で取り消されるのは待っていた文だけです。
1205 を受けたら ROLLBACK してからトランザクションをやり直します。innodb_rollback_on_timeout は実行中に変えられません(SET GLOBAL は ERROR 1238 ... read only variable)。設定ファイルに書いて再起動する必要があります。
違う行なのに待たされる(索引の無い列)
UPDATE acct SET ... WHERE name = 'c'(name に索引なし)をコミット前で止め、別の接続から id=5 の行を UPDATE しました。
name の索引 |
止めている側のレコードロック数 | id=5 の UPDATE |
|---|---|---|
| なし | 6(5行の表) | 1205 |
| あり | 3 | 通る |
索引の無い列で絞った UPDATE / DELETE は、全行を読みながらロックを取ります。関係のない行の更新まで待たされるときは、WHERE の列に索引があるかを EXPLAIN で確かめます。
ALTER TABLE でも 1205 が出る
開いたままのトランザクションが表を SELECT しているときに ALTER TABLE を実行すると、メタデータロックを待ちます。こちらの上限は innodb_lock_wait_timeout ではなく lock_wait_timeout(既定 31536000 秒=1年)です。
mysql> SET SESSION lock_wait_timeout = 3;
mysql> ALTER TABLE acct ADD COLUMN note VARCHAR(10);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
エラー番号とメッセージは行ロックのときと同じなので、1205 が ALTER TABLE などの DDL で出たらメタデータロックを疑います。待っている間の見え方は ALTER TABLE の記事に書きました。
待ち時間を変える
SET SESSION innodb_lock_wait_timeout = 10; -- この接続だけ
SET GLOBAL innodb_lock_wait_timeout = 10;
SET GLOBAL で 7 にしても、その接続の @@SESSION は 50 のままでした。7 になったのは新しく接続したセッションだけです。接続プールを使っているアプリは、プールの接続を作り直すか、接続時に SET SESSION を実行するように設定します。
1205 はエラーログ(/var/log/mysql/error.log)には残りませんでした。あとから追うには、アプリ側でエラーを記録するか、待っている間に sys.innodb_lock_waits を定期的に保存します。デッドロック(ERROR 1213)は待たずにすぐ返るエラーで、別の記事で扱っています。
関連: MySQLのERROR 1213「Deadlock found」 / MySQLのALTER TABLE / MySQLのEXPLAINの見方 / PostgreSQLのロック待ちを調べる