线上MySQL Too many connections报错如何快速扩容排查?
多数连接过多源于连接未释放而非连接数不足。需超级权限登录MySQL,检查Threads_running判断。临时扩容受系统文件描述符和内存限制,关键应用连接池空闲超时应不大于MySQL的等待超时。永久修改配置文件中最大连接数、等待超时等参数并验证语法。
先别急着动 max_connections,90% 的 "Too many connections" 不是连接不够用,而是连接没释放、堆在那儿占坑——得先确认是不是真连满了,再决定扩不扩容。
如何快速判断 MySQL 连接是否真的耗尽
哪怕应用连不上,MySQL 会预留一个 SUPER 权限的紧急连接位(max_connections + 1),所以还能用 socket 登进去:
- 执行
SHOW VARIABLES LIKE 'max_connections';—— 查看连接上限,默认值通常为 151 - 执行
SHOW 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; 看似快,但有三道硬门槛拦着:
- Linux 系统级文件描述符限制:
ulimit -n默认常为 1024,设到 1000 就可能失败;Docker 容器里没加--ulimit nofile=65536:65536,光改 MySQL 配置无效 - 已经连不上了?那这条命令根本执行不了——得靠
kill -TERM主进程(不是mysqld_safe)安全重启 - 内存扛不住:每个连接平均吃 512KB~2MB,设到 2000 连接,光连接本身就要 1~4GB 内存,容易触发 OOM
连接池配置比 MySQL 参数更关键
多数线上事故根子在应用侧。比如 Druid 或 HikariCP,常见错配:
max-active(或maximumPoolSize)设得比max_connections还高,多个服务一起压就爆min-idle和max-wait没调,连接用完不归还、等超时才扔,堆满SleepidleTimeout(连接池) >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 连接背后有没有未提交事务、慢查询或异常退出的脚本——这些才是反复爆满的伏笔。
