调大max_connections只是掩盖问题,根因在于连接生命周期管理不当,如应用未释放连接、连接池配置错误或长事务阻塞,易引发内存压力与锁竞争。

为什么 Too many connections 不是配置调大就完事?
MySQL 报 Too many connections,表面看是 max_connections 设低了,但真实根因往往藏在连接生命周期管理里。数据库连接不是“用完即关”的资源,一旦应用端没正确释放(比如没调用 connection.close()、连接池配置失当、长事务阻塞),连接就会堆积并最终耗尽。单纯调高 max_connections 只是掩盖问题,还可能加剧内存压力和锁竞争。
查当前谁占着连接不放:SHOW PROCESSLIST 要看什么
执行 SHOW PROCESSLIST 或更全的 SELECT * FROM information_schema.PROCESSLIST,重点盯三列:
-
State是Sleep但Time超过 60 秒 → 很可能是应用拿了连接没归还,或连接池 idle timeout 没生效 -
Command是Query且Time持续增长 → 正在跑慢 SQL,可能卡住整个连接 -
User和Host集中在某几个应用 IP → 定位到具体服务,而不是所有连接都均匀分布
注意:root 用户的连接也得看——运维脚本或监控工具如果没设连接超时,也可能悄悄吃掉配额。
连接池配置怎么才算合理?
Java 应用常见用 HikariCP,Python 常用 SQLAlchemy + Pools,它们的默认值往往不适合生产:
- HikariCP 的
maximumPoolSize别盲目设成 100+;应按接口 QPS × 平均响应时间(秒)× 安全系数(1.5~2)估算,再结合 DB 的max_connections反推上限 - 必须设
connection-timeout(如 30000)和idle-timeout(如 600000),否则空闲连接永远不释放 - 开启
leak-detection-threshold(如 60000),能捕获忘记 close() 的代码路径 - SQLAlchemy 的
pool_recycle建议设为 3600,避免 MySQL 的wait_timeout(默认 28800)提前断连引发异常
如何确认是突发流量还是连接泄漏?
靠单次 SHOW PROCESSLIST 不够,要连续观察趋势:
- 用
SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Threads_connected';每 10 秒采一次,画折线图——如果是缓慢爬升后卡在高位,基本是泄漏;如果是尖峰冲顶后回落,才是流量问题 - 配合应用日志查
Connection borrow timeout或Cannot get JDBC connection类错误,定位到具体方法栈 - 检查 MySQL 错误日志里有没有频繁的
Aborted connection,这常意味着客户端异常断连,而服务端连接未及时清理
真正难排查的是“半泄漏”:连接被归还给池,但池认为它还可用,其实底层 socket 已失效,下次取出时才报错——这种得靠连接测试语句(如 SELECT 1)+ test-on-borrow 配合抓包验证。










