lock wait timeout exceeded是锁等待超时而非死锁,需查innodb_trx中trx_state='running'且trx_started远早于当前时间的持锁事务,再联查innodb_lock_waits确认blocking_trx_id,kill对应trx_mysql_thread_id线程。

查 INNODB_TRX 找出“卡住不动”的事务
锁等待超时(Lock wait timeout exceeded)不是随机发生的,它背后一定有另一个长时间运行、未提交的事务在持锁。最直接的突破口是 INNODB_TRX 表:它记录了所有活跃事务的实时状态。重点关注 trx_state = 'RUNNING' 且 trx_started 时间远早于当前时间的记录——比如已运行 2 分钟以上,基本就是它。
常见误判点:
- 只看
trx_state = 'LOCK WAIT':这是被堵住的受害者,不是真凶 - 忽略
trx_query字段:里面可能藏着没提交的UPDATE或手工执行后忘COMMIT的语句 - 把
trx_id当成线程 ID:真正要 KILL 的是trx_mysql_thread_id
用 INNODB_LOCK_WAITS 确认阻塞链关系
INNODB_LOCK_WAITS 是唯一能明确告诉你“谁在等谁”的表。它提供两个关键 ID:BLOCKING_TRX_ID(持锁者)和 REQUESTED_LOCK_ID(等待者)。但注意:这张表只在锁等待真实发生时才有数据;一旦超时回滚或锁释放,记录就消失了。
实用技巧:
- 别单独查它,一定要 JOIN
INNODB_TRX把BLOCKING_TRX_ID映射回具体线程和 SQL - 如果查不到结果,不代表没锁,可能是等待刚结束、或已退化为死锁(此时要去查
SHOW ENGINE INNODB STATUS中的LATEST DETECTED DEADLOCK) -
blocking_trx_id对应的事务,其trx_state几乎总是RUNNING,而不是LOCK WAIT
KILL 前先确认是不是元数据锁(MDL)
如果 PROCESSLIST 里看到 STATE = 'Waiting for table metadata lock',说明不是行锁/间隙锁的问题,而是 DDL 操作(如 ALTER TABLE)在等元数据锁。这时查 INNODB_TRX 和 INNODB_LOCK_WAITS 是无效的,得换路径:
- 查
performance_schema.metadata_locks(MySQL 5.7+)定位持有 MDL 的会话 - 配合
performance_schema.threads和events_statements_current找到对应 SQL - DDL 阻塞往往比行锁更隐蔽,因为一个慢查询就能让后续所有 DML 卡在 MDL 上
为什么不能只调大 innodb_lock_wait_timeout
这个参数(默认 50 秒)只控制“等多久就放弃”,不改变“为什么等”。设成 300 秒只会让问题更难发现:
- 用户端卡 5 分钟才失败,体验断层更严重
- 阻塞链拉得更长,可能引发连接池耗尽
- 掩盖了真实根因:比如缺失索引导致全表扫描加锁、事务里混了 HTTP 调用、或批量
INSERT撞自增锁 - 线上核心接口建议设为 5 或 10 秒——失败快,前端能及时降级或重试
真正要盯住的,是 trx_started 时间差、trx_query 内容、以及是否走索引(用 EXPLAIN 验证),这些才是锁等待的源头证据。











