答案是连接泄漏而非真耗尽:因事务未提交、资源未关闭或wait_timeout与max-lifetime不匹配,导致HikariCP ActiveCount远超MySQL Threads_connected,且leak-detection未触发。

这通常不是连接池真“耗尽”,而是连接被卡在不可见状态——比如事务未提交、长事务阻塞、或连接被异常线程持有但未归还。
为什么 SHOW PROCESSLIST 看不到大量活跃连接,但应用却报 Timeout waiting for available connection
因为 HikariCP 或 Druid 的 ActiveCount 统计的是“已借出且未归还”的连接数,而 MySQL 的 Threads_connected 只反映当前 TCP 连接数。两者不一致的常见原因有:
- 连接确实被借出,但执行完 SQL 后没关闭
ResultSet/Statement,导致连接无法归还池中(即使事务已提交) - 事务开启后抛异常,但没走
rollback()或未进finally块,连接一直挂在事务里,SHOW PROCESSLIST显示State = "Sleep"但Command = "Sleep"、Time > wait_timeout,实际仍被占用 - 应用线程因锁竞争、RPC 超时、GC 停顿等原因卡住,连接被借出后长期未调用
close(),池内连接数持续上涨,但 MySQL 端连接可能已被服务端主动断开(表现为State = "Closed"或消失),而池端未感知 - HikariCP 的
leak-detection-threshold未启用,或阈值设得过大(如 60000 毫秒),导致短时泄漏漏检
如何确认是连接泄漏而非配置不足
先绕过“看日志”这种低效方式,直接查三处关键指标:
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
- 运行
SELECT * FROM performance_schema.threads WHERE TYPE = 'FOREGROUND' AND PROCESSLIST_COMMAND != 'Sleep';—— 查真正干活的线程,排除假休眠 - 对比应用端监控:HikariCP 的
HikariPool-1.ActiveConnections(JMX)和 MySQL 的Threads_connected。若前者远大于后者,基本可断定泄漏 - 启用
leak-detection-threshold=30000并观察日志是否频繁输出Connection leak detection triggered,同时检查对应堆栈中是否有未关闭资源的代码路径(如PreparedStatement在 try 块外声明、ResultSet未 close)
排查时最容易忽略的两个细节
一是 wait_timeout 和 max-lifetime 不匹配:MySQL 默认 wait_timeout=28800(8 小时),而 HikariCP max-lifetime 若设为 1800000(30 分钟),连接会在池中老化失效,但应用层可能还在用这个“半死”连接,触发重连逻辑并卡住;
二是 Spring 的 @Transactional 传播行为误用:REQUIRES_NEW 嵌套事务未正确捕获异常,外层事务回滚但内层连接未释放,尤其在异步方法或定时任务中极易复现。
这类问题不会立刻报错,但会缓慢蚕食连接池——等你看到告警,往往已有 5–10 个连接卡了十几分钟,而 SHOW PROCESSLIST 里只显示几个“正常”连接。

















