答案是:先查threads_connected与threads_running是否严重失衡,再确认wait_timeout和连接池配置是否匹配;90%的“too many connections”源于应用未释放连接或连接池配错,而非max_connections过小。

刚搭好的 MySQL 别急着调 max_connections,先确认它是不是真瓶颈——默认 151 连接对多数新环境已够用,盲目调高反而容易触发系统限制或内存溢出。
怎么快速验证当前连接数是否真不够用
哪怕应用连不上,root 本地 socket 还能进(MySQL 预留一个紧急连接位):
- 执行
SHOW VARIABLES LIKE 'max_connections';看上限(新实例通常为 151) - 执行
SHOW STATUS LIKE 'Threads_connected';看当前真实连接数 - 再查
SHOW STATUS LIKE 'Threads_running';—— 如果Threads_connected接近上限但Threads_running只有 1~3,说明全是 Sleep 连接堆着不放,不是上限低,是应用没关连接或连接池配错
临时救急:SET GLOBAL max_connections 能不能立刻生效
能,但三道硬门槛常让它“看似执行成功实则无效”:
- 执行前先跑
ulimit -n:若返回 1024,而你想设 2000,MySQL 启动时会自动截断到 1024,SET GLOBAL也改不动 - systemd 管理的服务(Ubuntu 16.04+/CentOS 7+)默认
LimitNOFILE=1024,必须编辑/usr/lib/systemd/system/mysqld.service,在[Service]下加LimitNOFILE=65536,再systemctl --system daemon-reload && systemctl restart mysqld - 如果已经连不上了,
SET GLOBAL根本执行不了——这时候只能靠重启或kill -TERM $(pidof mysqld)安全终止后重拉
永久生效:配置文件里写对位置比数值更重要
常见失效原因不是数值小,而是配置根本没加载:
- 确认配置写在
[mysqld]段下,不是[client]或全局段;写错段落等于没写 - MySQL 启动只读一个主配置文件,用
mysqld --verbose --help | grep "Default options"查实际加载路径(常见于/etc/my.cnf、/etc/mysql/my.cnf或/etc/mysql/mysql.conf.d/mysqld.cnf) - MySQL 8.0.22+ 支持
SET PERSIST max_connections = 300;,它会写入mysqld-auto.cnf,优先级高于 my.cnf —— 若已用此方式,改配置文件也不覆盖 - 重启后务必验证:
SELECT @@global.max_connections;,别只信配置文件内容
比调参更关键的:连接池 idleTimeout 必须短于 wait_timeout
90% 的 “Too many connections” 根源不在数据库侧,而在应用连接池配置失当:
- 检查
wait_timeout(默认 28800 秒,即 8 小时):执行SHOW VARIABLES LIKE 'wait_timeout'; - 对比你的连接池参数:HikariCP 的
idleTimeout、Druid 的minEvictableIdleTimeMillis必须 严格小于wait_timeout,否则连接永远归还不回去 - PHP 等脚本语言发生 fatal error 时,
mysqlnd不会自动 close,必须显式调mysqli_close()或用try/finally保证释放 - 临时清理堆积:用
SELECT USER, HOST, COUNT(*) FROM information_schema.PROCESSLIST GROUP BY USER, HOST;定位异常来源,再KILL对应 ID
刚搭好的环境最容易忽略的是连接池与 wait_timeout 的时间差,以及 systemd 的 LimitNOFILE 限制——这两点不处理,调再大的 max_connections 都只是把报错延迟几分钟而已。











