MySQL 连接数超限的典型表现
看到
Too many connections错误,或应用日志里频繁出现连接拒绝、超时,基本可以确认是 MySQL 的最大连接数被耗尽。这不一定是业务量暴增导致的,更常见的是连接未正确释放、连接池配置失当、或短连接滥用。
max_connections是 MySQL 服务端硬限制,默认通常为 151(MySQL 5.7+),可通过
SHOW VARIABLES LIKE 'max_connections';查看 实际活跃连接数可查
SHOW STATUS LIKE 'Threads_connected';,注意它包含空闲连接,不代表都在干活 真正危险的是
Threads_running持续偏高,说明有大量查询在排队或阻塞
Java 应用中 HikariCP 连接池关键配置项
HikariCP 是目前最主流的 JDBC 连接池,它的默认行为对 MySQL 很友好,但若不做调整,极易因“保守”或“激进”引发问题。
maximumPoolSize:不要盲目设成 100 或 200。建议初始值设为
2 × (CPU 核数) + 1,再根据压测中
Threads_running和应用 RT 调整
minimumIdle:设为与
maximumPoolSize相同(即固定大小池),可避免动态扩缩带来的抖动;但若应用流量波峰波谷明显,可设为
maximumPoolSize × 0.3
connectionTimeout:建议 30000(30 秒),太短会让业务误报失败,太长会拖垮线程池
idleTimeout:MySQL 默认
wait_timeout=28800(8 小时),HikariCP 的
idleTimeout必须小于它,否则连接可能被 MySQL 主动断开后,池子还傻等——推荐设为 10 分钟(600000)
keepaliveTime:仅在
minimumIdle 时生效,用于定期探测空闲连接是否存活,设为 300000(5 分钟)较稳妥
MySQL 侧必须同步调整的几个参数
光调应用层没用,MySQL 本身也得配合。否则连接池以为连接还活着,MySQL 却已悄悄关掉,结果就是
Connection reset或
Communications link failure。
wait_timeout和
interactive_timeout必须一致,且建议设为 600(10 分钟)或 1800(30 分钟),不能留默认 8 小时
max_connections不宜设得过高(比如 5000)。每个连接至少占用 256KB 内存,上万连接可能直接吃光服务器内存;应优先优化单连接效率和池复用率 开启
skip_name_resolve:避免 DNS 反查拖慢连接建立,尤其在容器或云环境里特别明显 检查是否有长期未关闭的
SLEEP状态连接:
SELECT ID, USER, HOST, DB, COMMAND, TIME, STATE FROM INFORMATION_SCHEMA.PROCESSLIST WHERE COMMAND = 'Sleep' AND TIME > 60;—— 找出源头代码里的漏掉
close()的地方
排查连接泄漏的实操路径
连接数缓慢上涨、重启后回落,大概率是泄漏。别只盯着连接池配置。
在应用启动时开启 HikariCP 的 debug 日志:logging.level.com.zaxxer.hikari=DEBUG,重点看
Connection leak detection相关输出 使用
leakDetectionThreshold(单位毫秒),例如设为 60000(1 分钟),一旦连接被借出超过该时间未归还,HikariCP 会打印堆栈 数据库侧执行
SHOW PROCESSLIST;,按
TIME倒序,重点关注
Command=Sleep且
Time > 300的连接,结合
Info列(如果非 NULL)判断是哪类查询残留 检查代码中所有
Connection、
PreparedStatement、
ResultSet是否都在
finally块或 try-with-resources 中显式关闭;JDBC 4.0+ 后者更可靠
MySQL 连接问题很少是单点故障,往往是池配置、服务端参数、代码习惯三者叠加出的问题。最容易被忽略的是
wait_timeout和
idleTimeout的数值错位,以及没有开启连接泄漏检测。
