快速定位死锁需结合processlist筛选活跃连接与performance_schema.data_locks(8.0+)或show engine innodb status查锁等待链,重点分析transactions和lock wait部分。

怎么快速找到正在死锁的 MySQL 连接
死锁不是某个连接“卡住”了,而是两个或多个事务互相等待对方释放锁,MySQL 自动选一个做 ROLLBACK,但被回滚的连接可能还留在 PROCESSLIST 里挂着——尤其在应用没正确处理异常时。真正要清理的,是那些状态为 Locked、Waiting for table metadata lock 或长时间 Updating/Deleting 却没进展的会话。
别只看 SHOW PROCESSLIST,它默认不显示所有用户进程,也看不到事务锁信息:
- 用
SELECT * FROM information_schema.PROCESSLIST WHERE COMMAND != 'Sleep' AND TIME > 60;筛出活跃且持续超 60 秒的连接 - 配合
SELECT * FROM performance_schema.data_locks;(MySQL 8.0+)或SHOW ENGINE INNODB STATUS\G查具体锁等待链——重点看TRANSACTIONS和LOCK WAIT部分 - 注意:普通用户查
information_schema.PROCESSLIST只能看到自己的连接,需SUPER或CONNECTION_ADMIN权限才看全
KILL 命令为什么有时不生效
KILL 不是强制杀操作系统线程,而是向 MySQL Server 发送中断信号,能否立刻终止取决于当前线程所处状态。比如正在执行大事务回滚、写 binlog、刷脏页或等系统 I/O,KILL 后会显示 Killed 状态,但实际退出可能延迟几十秒甚至更久。
- 用
KILL CONNECTION <code>id(推荐),不是过时的KILL <code>id;后者在 MySQL 5.7+ 已等价于前者,但语义更清晰 -
KILL QUERY <code>id只中断当前语句,不杀连接,适合想保留连接但停止慢查询的场景 - 如果
KILL后连接仍卡在Rolling back,说明事务回滚本身很重——此时硬等比强杀更安全,避免 InnoDB 状态不一致 - 禁止对
system user或主从复制线程(如Connect状态的slave_sql)执行KILL,可能中断复制
如何避免 KILL 后又立刻出现新死锁
清理单个死锁进程只是止痛,不是治病。死锁高频复现,说明业务逻辑或 SQL 设计有根本问题。
- 检查是否在事务里调用非确定性函数(如
NOW()、RAND())或跨库更新,导致加锁顺序不可控 - 确认所有涉及多表更新/删除的 SQL,是否始终按相同顺序访问表(例如总先
UPDATE orders再UPDATE order_items) - 避免在事务中嵌套应用层循环(如 foreach 更新 1000 行),改用批量语句或拆成小事务
- 监控
Innodb_row_lock_waits和Innodb_deadlocks状态变量,用SHOW GLOBAL STATUS LIKE 'Innodb_deadlocks';看累计次数
MySQL 5.7 和 8.0 在死锁诊断上的关键差异
MySQL 8.0 把锁信息从黑盒日志搬到可查视图,排查效率高很多;5.7 则严重依赖 SHOW ENGINE INNODB STATUS 的文本解析,容易漏掉瞬时死锁。
- 8.0 必用:
performance_schema.data_locks+data_lock_waits+threads关联查谁在等谁 - 5.7 只能靠
SHOW ENGINE INNODB STATUS\G中的LATEST DETECTED DEADLOCK段,但该段只保留最近一次死锁,且不记录完整 SQL - 两者都需开启
innodb_print_all_deadlocks = ON(写入 error log),否则只有最近一次会被记录 - 注意:8.0 默认关闭
performance_schema的锁相关 instrument,要手动开:UPDATE performance_schema.setup_instruments SET ENABLED = 'YES' WHERE NAME LIKE 'wait/lock%';
死锁清理最麻烦的从来不是命令怎么敲,而是你不确定那个 ID 对应的到底是前端重试请求、定时任务还是某个早该下线的老服务。建议每次 KILL 前,先用 SELECT USER, HOST, DB, INFO FROM information_schema.PROCESSLIST WHERE ID = <code>xxx; 确认来源——尤其是 HOST 字段,常藏着代理 IP 或容器内网地址。











