90%的“Too many connections”源于应用层连接未释放,而非max_connections配置过小;应先用socket直连执行SHOW VARIABLES LIKE 'max_connections'和SHOW STATUS LIKE 'Threads_connected'确认是否真满,再结合Threads_running与Max_used_connections分析水位,同步检查ulimit、systemd限制及连接池配置。

直接调大 max_connections 只能临时缓解,90% 的 Too many connections 根源在应用层连接没释放,不是数据库配小了。
怎么快速确认是不是真连满了
别急着改配置,先用 socket 直连(哪怕应用连不上)执行两条命令:
-
SHOW VARIABLES LIKE 'max_connections';—— 看上限,默认 MySQL 5.7/8.0 是 151 -
SHOW STATUS LIKE 'Threads_connected';—— 看当前已建连数,再对比Threads_running
如果 Threads_connected 接近 max_connections,但 Threads_running 很小(比如 498 vs 3),说明大量连接卡在 Sleep 状态,基本是应用没 close() 或连接池 leak。
Max_used_connections 才是关键水位指标:长期 >90% 就该预警,不是等报错才查。
为什么 SET GLOBAL max_connections 经常不生效
常见现象:执行 SET GLOBAL max_connections = 1000; 后查变量还是旧值。根本卡点不在 MySQL 配置本身,而在系统级限制:
- 运行
ulimit -n,若返回 1024,而你想设 2000,MySQL 启动时会自动向下取整到 1024 - systemd 管理的 MySQL/MariaDB 必须在
/usr/lib/systemd/system/mysqld.service的[Service]段加:LimitNOFILE=65536LimitNPROC=65536
然后执行systemctl --system daemon-reload && systemctl restart mysqld - MySQL 8.0.22+ 支持
SET PERSIST max_connections = 1000;,会写入mysqld-auto.cnf,优先级高于my.cnf—— 若已用此方式,改my.cnf不覆盖
kill Sleep 连接只是应急,不是解法
SHOW PROCESSLIST; 里看到一堆 Sleep 连接,kill 掉能抢出几个名额,但几小时后又满——因为泄漏还在继续。
- 重点查
USER和HOST:用SELECT USER, HOST, COUNT(*) FROM information_schema.PROCESSLIST GROUP BY USER, HOST;定位异常 IP 或账号 - Java 应用用 HikariCP 时,
connection-timeout默认 30 秒,网络抖动易堆积;建议设为 10–15 秒,并开leak-detection-threshold - PHP 脚本若发生
fatal error,mysqlnd 不会自动归还连接;必须显式mysqli_close()或依赖脚本结束自动释放(不可靠) - 连接池最大数(如
maximumPoolSize)应 ≤max_connections的 70%,留余量给后台线程和管理员连接
wait_timeout 和 interactive_timeout 必须配对调低
这两个参数决定空闲连接多久被服务端强制断开。默认 28800 秒(8 小时),意味着一个忘了 close() 的连接能占坑一整天。
- 在
[mysqld]段加:wait_timeout = 300interactive_timeout = 300
即 5 分钟无活动就断开 - 注意:应用连接池的
idleTimeout必须 短于 这个值,否则池内连接会被 MySQL 先断,下次复用时报错 - 云数据库(如阿里云 RDS、腾讯云 CDB)可能额外限制“活跃会话数”,和
max_connections无关,得去控制台看配额
真正难的不是调参,而是让每个连接都有明确的生命周期终点——这需要代码里每条 Connection 都落在 try-with-resources 或 finally 块里,而不是靠配置兜底。


















