先确认是否真连满:用root本地socket登录后执行三句——SHOW VARIABLES LIKE 'max_connections'; SHOW STATUS LIKE 'Threads_connected'; SHOW STATUS LIKE 'Max_used_connections'; 若Threads_connected接近上限但Threads_running极低,说明是Sleep连接堆积。
别急着改配置。哪怕应用连不上,用 root 通过本地 socket 还能进——MySQL 预留一个紧急连接位,专留给有 SUPER 权限的管理员。
登录后立刻执行三句:
SHOW VARIABLES LIKE 'max_connections';——看上限,默认常是 151SHOW STATUS LIKE 'Threads_connected';——当前已建连数SHOW STATUS LIKE 'Max_used_connections';——历史峰值,比瞬时值更可靠如果 Threads_connected 接近 max_connections,但 Threads_running 极低(比如 500 连接里只有 2 个在跑),说明全是 Sleep 状态,基本就是泄漏或空闲连接堆积。
执行 SET GLOBAL max_connections = 1000; 后查变量还是旧值?卡点不在 MySQL 本身,而在三道硬限制:
ulimit -n,若返回 1024,而你想设 2000,MySQL 启动时会自动向下取整/usr/lib/systemd/system/mysqld.service 的 [Service] 段加:LimitNOFILE=65536 和 LimitNPROC=65536,再执行 systemctl --system daemon-reload && systemctl restart mysqld
SET PERSIST max_connections = 1000;,它写入 mysqld-auto.cnf,优先级高于 my.cnf——若已用此方式,改配置文件也不覆盖多数线上事故根子在应用侧。比如 HikariCP 或 Druid 常见错配:
max-active(Druid)或 maximumPoolSize(HikariCP)设得比 max_connections 还高,多个服务一起压就爆wait_timeout 设为 300 秒,但连接池的 idleTimeout 设成 600 秒,连接永远归还不回去connection-timeout 默认 30 秒,网络抖动易堆积;建议调到 10–15 秒,并开 leak-detection-threshold
关键原则:idleTimeout 必须严格小于 wait_timeout,否则连接被 MySQL 断掉后,池子还当它活着,下次用就报错。
SHOW PROCESSLIST; 里看到一堆 Sleep 连接,KILL 掉能抢出几个名额,但几小时后又满——因为泄漏还在继续。
重点查 USER 和 HOST:
SELECT USER, HOST, COUNT(*) FROM information_schema.PROCESSLIST GROUP BY USER, HOST; 定位异常 IP 或账号KILL <code>ID; 逐个终止;不要用 KILL QUERY,它只停语句,连接还占着SET GLOBAL wait_timeout = 120;(非交互式连接 2 分钟自动断),SET GLOBAL interactive_timeout = 180;(交互式连接 3 分钟)真正复杂的是那些没显式关连接的代码路径:PHP 脚本发生 fatal error 时,mysqlnd 不会自动归还连接,必须显式 mysqli_close();Java 里 try 块里忘了 finally { conn.close() },也一样堆满。