90%的“Too many connections”源于连接未释放而非max_connections过小;应先用socket直连执行SHOW VARIABLES LIKE 'max_connections'、SHOW STATUS LIKE 'Threads_connected'和SHOW STATUS LIKE 'Threads_running'确认是否真满,若Threads_connected接近上限而Threads_running极低,说明大量连接卡在Sleep状态,多为应用未关闭或连接池配置不当。
别急着调 max_connections,90% 的 “Too many connections” 不是连接不够用,而是连接没释放、堆在那儿占坑——先确认是不是真连满了,再决定扩不扩容。
哪怕应用连不上,MySQL 会预留一个 SUPER 权限的紧急连接位(max_connections + 1),所以你还能用 socket 登进去:
SHOW VARIABLES LIKE 'max_connections'; —— 看上限,默认常是 151SHOW STATUS LIKE 'Threads_connected'; —— 看当前已建连数SHOW STATUS LIKE 'Threads_running'; —— 看正在干活的线程数如果 Threads_connected 接近上限,但 Threads_running 极低(比如 2/498),说明几百个连接全卡在 Sleep 状态,基本就是应用没关连接或连接池 idleTimeout 比 MySQL 的 wait_timeout 还长。
SET GLOBAL max_connections = 1000; 看似快,但有三道硬门槛拦着:
ulimit -n 默认常为 1024,设到 1000 就可能失败;Docker 容器里没加 --ulimit nofile=65536:65536,光改 MySQL 配置无效kill -TERM 主进程(不是 mysqld_safe)安全重启多数线上事故根子在应用侧。比如 Druid 或 HikariCP,常见错配:
max-active(或 maximumPoolSize)设得比 max_connections 还高,多个服务一起压就爆min-idle 和 max-wait 没调,连接用完不归还、等超时才扔,堆满 Sleep
idleTimeout(连接池) > wait_timeout(MySQL),导致连接池以为连接还活着,MySQL 却已单方面断开,后续复用时报错或卡死正确做法是:连接池 idleTimeout 必须 ≤ MySQL 的 wait_timeout,建议都设成 300 秒(5 分钟)起手,再根据业务微调。
编辑 /etc/my.cnf 或 /etc/mysql/my.cnf,在 [mysqld] 段加:
max_connections = 500wait_timeout = 300interactive_timeout = 300max_user_connections = 100
注意:max_user_connections 是防止单个应用(比如某个微服务)占满所有连接,留余量给管理账号和其它服务。改完必须验证语法:mysqld --validate-config,并确认没被其他配置文件覆盖(mysqld --verbose --help | grep "Default options" 查加载顺序)。
真正难的不是改数字,而是确认每个 Sleep 连接背后有没有未提交事务、慢查询或异常退出的脚本——这些才是反复爆满的伏笔。