锁等待本身不消耗连接但会阻塞连接释放,导致连接池耗尽;需通过SHOW PROCESSLIST等命令定位卡住的线程和长事务,并配合wait_timeout、innodb_lock_wait_timeout等参数优化,同时规范应用层事务管理和连接回收。

锁等待怎么把连接池吃光的
锁等待本身不消耗连接,但会拖住连接不释放——事务没提交、查询卡在 Waiting for table metadata lock 或 Waiting for lock 状态时,那个连接就一直占着不放。如果应用层没设查询超时、又没用连接池的 idle timeout,几十个卡住的连接就能把 max_connections 填满,新请求直接被拒,报错 Too many connections。
常见场景:线上执行 ALTER TABLE 时没选低峰期,或长事务里混了慢查询;另一个是应用里开了事务但忘了 COMMIT 或 ROLLBACK,连接挂在那里不动。
查锁和卡住的连接,别只看 max_connections
调高 max_connections 是掩耳盗铃,得先定位谁在堵路。连上 MySQL 后优先跑这三条:
-
SHOW PROCESSLIST—— 找状态是Locked、Waiting for table metadata lock、Sleep但Time超过 60 秒的线程 SELECT * FROM performance_schema.threads WHERE PROCESSLIST_STATE = 'Waiting for table metadata lock';-
SELECT * FROM information_schema.INNODB_TRX ORDER BY TRX_STARTED LIMIT 5;—— 看有没有运行太久的事务
注意:performance_schema 默认可能没开全,setup_instruments 里要确保 wait/lock/metadata/sql/mdl 和 transaction 相关项是 ENABLED。
真正管用的配置组合(不是单调 max_connections)
max_connections 只是最后一道闸门,关键在提前拦住问题连接。这几个参数必须一起调:
-
wait_timeout和interactive_timeout:设成 60–300(秒),避免空闲连接长期挂着;应用用连接池的话,这个值应 ≤ 池的 idle timeout -
innodb_lock_wait_timeout:默认 50 秒,对 OLTP 业务建议压到 10–25 秒,让锁冲突更快失败,而不是无限等 -
lock_wait_timeout(会话级):可在应用连接初始化时执行SET SESSION lock_wait_timeout = 10;,比全局设更灵活 -
max_connections本身:别硬拍脑袋,按峰值并发 ×(1.5–2)估算,但上限建议 ≤ 2000(太高反而加剧上下文切换开销)
改完记得 SELECT @@max_connections; 和 SELECT @@innodb_lock_wait_timeout; 确认生效,有些变量需要重启,有些动态生效。
应用层不配合,DB 配置再好也白搭
所有服务端配置都防不住应用里的坏习惯。最容易被忽略的是:
- 没显式控制事务边界:用 ORM 时,
@Transactional作用域过大,或嵌套调用没处理传播行为,导致事务意外延长 - 连接未归还池:异常分支里漏了
connection.close()或没进finally块 - 批量操作没分页:一次
UPDATE几十万行,锁表时间远超innodb_lock_wait_timeout,直接卡死
上线前跑一次锁竞争压测,比调参重要得多——比如用 pt-kill 杀掉长时间运行的查询,看应用是否能自动重试或降级,这才是真实防线。


















