最有效方式是kill connection线程id,需先通过innodb_trx定位trx_state='running'且trx_query is null、运行超30秒的事务,取trx_mysql_thread_id执行kill,事后验证innodb_trx是否清空。

直接 KILL 线程 ID 是最常用手段,但“优雅”不在于快,而在于不误杀、不残留、不引发连锁回滚风暴——关键得先确认它真在阻塞别人,且杀完能真正释放锁。
查谁在真正阻塞业务:别只看 SHOW PROCESSLIST
状态为 Sleep 或 Query 但 TIME 很大的连接,不等于它在阻塞;很多长事务根本不出现在 PROCESSLIST 的等待态里。真正要盯的是:
-
INFORMATION_SCHEMA.INNODB_TRX中trx_state = 'RUNNING'且trx_query IS NULL的事务——说明它只执行了BEGIN,后续没 SQL,极大概率是客户端忘了COMMIT或崩溃了 -
TRX_STARTED时间戳比当前早超过 60 秒(生产建议设为 30 秒),这是比TIME更可靠的判断依据 - 结合
performance_schema.data_lock_waits(MySQL 8.0+)或INNODB_LOCK_WAITS(5.7)定位阻塞链:找出BLOCKING_TRX_ID对应的trx_mysql_thread_id,这才是该杀的目标
KILL TRANSACTION 还是 KILL CONNECTION?看版本和场景
MySQL 5.7+ 支持 KILL TRANSACTION <code>TRX_ID,它只终止事务本身,连接保活,适合连接池环境;5.6 及更早只能用 KILL QUERY <code>ID 或 KILL <code>ID。但注意:
KILL QUERY <code>ID不会结束事务,TRX_STATE仍为RUNNING,锁不会释放——DDL 依然卡着KILL <code>ID(即KILL CONNECTION)会强制回滚整个事务并关闭连接,对持有 MDL 锁(如阻塞ALTER TABLE)的事务是唯一有效解- 严禁对
LOCK WAIT状态的等待方执行KILL——这只会让持锁者继续跑,其他请求照堵
杀完必须验证:锁是否真释放了?
KILL 命令返回成功 ≠ 锁已释放。InnoDB 回滚耗时取决于 TRX_ROWS_MODIFIED,大事务可能卡在 Rolling back 状态几分钟。此时:
- 不要重复执行
KILL——第二次会报Unknown thread id - 立刻查
INFORMATION_SCHEMA.INNODB_TRX是否已清空该事务记录,而不是只看PROCESSLIST里有没有那个 ID(线程 ID 可能被复用) - 若
TRX_OPERATION_STATE显示rolling back,且TRX_ROWS_MODIFIED很大,说明回滚中,需耐心等;此时新请求仍会被阻塞 - DDL 仍卡在
Waiting for table metadata lock?说明还有别的事务没被干掉,继续查data_lock_waits
最容易被忽略的是:一个只执行了 SELECT ... FOR UPDATE 就挂起的事务,哪怕没改任何数据,只要没 COMMIT,就一直拿着行锁和 MDL 读锁——这不是性能问题,是锁协议的刚性约束,必须亲手终结。











