结论:别急着改max_connections,先用root本地socket登录查清是真连满还是sleep堆积、连接池错配或慢查询卡死;90%问题源于连接未归还而非上限不足。

直接说结论:别急着改 max_connections,先用 root 本地 socket 登录,查清是真连满了,还是 Sleep 连接堆积、连接池错配或慢查询卡死。90% 的线上爆满都不是上限不够,而是连接没归还。
怎么确认是不是真连满了
哪怕应用全挂了,root 仍能通过本地 socket 进去——MySQL 预留一个紧急连接位给 SUPER 权限用户。登录后立刻执行三句:
-
SHOW VARIABLES LIKE 'max_connections';—— 看上限,默认常是 151 -
SHOW STATUS LIKE 'Threads_connected';—— 当前已建连数 -
SHOW STATUS LIKE 'Max_used_connections';—— 历史峰值,比瞬时值更可靠
如果 Threads_connected 接近上限,但 Threads_running 极低(比如 500 连里只有 2 个在跑),说明全是 Sleep,基本就是泄漏或空闲连接堆积。
为什么 SET GLOBAL max_connections 经常不生效
执行 SET GLOBAL max_connections = 1000; 后查变量还是旧值?卡点不在 MySQL 本身,而在三道硬限制:
- 运行
ulimit -n,若返回 1024,而你想设 2000,MySQL 启动时会自动向下取整 - systemd 管理的服务必须在
/usr/lib/systemd/system/mysqld.service的[Service]段加:LimitNOFILE=65536和LimitNPROC=65536,再执行systemctl --system daemon-reload && systemctl restart mysqld - MySQL 8.0.22+ 支持
SET PERSIST max_connections = 1000;,它写入mysqld-auto.cnf,优先级高于my.cnf——若已用此方式,改配置文件也不覆盖
连接池 idleTimeout 和 wait_timeout 必须匹配
多数线上事故根子在应用侧。比如 HikariCP 或 Druid 常见错配:
-
maximumPoolSize(HikariCP)或max-active(Druid)设得比max_connections还高,多个服务一起压就爆 -
wait_timeout设为 300 秒,但连接池的idleTimeout设成 600 秒,连接永远归还不回去 - HikariCP 的
connection-timeout默认 30 秒,网络抖动易堆积;建议调到 10–15 秒,并开leak-detection-threshold
关键原则:idleTimeout 必须严格小于 wait_timeout,否则连接被 MySQL 断掉后,池子还当它活着,下次用就报错。
kill Sleep 连接只是应急,不是解法
SHOW PROCESSLIST; 里看到一堆 Sleep 连接,KILL 掉能抢出几个名额,但几小时后又满——因为泄漏还在继续。重点查 USER 和 HOST:
SELECT USER, HOST, COUNT(*) FROM information_schema.PROCESSLIST GROUP BY USER, HOST;
定位异常 IP 或账号。真正要盯的是:哪个应用、哪个服务、哪段代码在打开连接后没 close,或者事务没 commit/rollback 就扔那儿了。这类问题不从代码层修复,调再大参数也白搭。











