MySQL5.7连接拒绝,连接数打满
MySQL5.7 出现 ERROR 1040 Too many connections 或应用提示连接拒绝时,十有八九是连接数被打满,而 wait_timeout 设置太长又会让空闲连接一直占着位置。
本文按排查、调整、验证的顺序,帮你把这个问题彻底解决。
先确认连接数是不是真的满了
登录数据库执行下面两条命令,先看当前状态:
SHOW VARIABLES LIKE 'max_connections';
SHOW STATUS LIKE 'Threads_connected';
max_connections表示最大连接数,默认通常是 151。Threads_connected表示当前已建立的连接数。
如果 Threads_connected 已经接近或等于 max_connections,那就是连接数被打满了。
再执行 SHOW STATUS LIKE 'Aborted_connects';,如果这个值很大,说明大量连接被拒绝,需要尽快处理。
调整 max_connections 与 wait_timeout
连接数不够用,最直接的办法是调大上限。
打开 MySQL 配置文件 /etc/my.cnf(也可能在 /etc/mysql/mysql.conf.d/mysqld.cnf),在 [mysqld] 段下修改或新增:
max_connections = 500
wait_timeout = 60
interactive_timeout = 60
wait_timeout 是普通连接的空闲超时时间,默认 28800 秒(8 小时)。
对大部分 web 应用来说,60 秒足够用,改小之后空闲连接能被更快回收,避免连接堆积。interactive_timeout 也要一起改,否则命令行连接还是按原来的默认值走。
改完重启 MySQL:
systemctl restart mysqld
如果不想重启实例,也可以动态修改,但重启后仍会失效:
SET GLOBAL max_connections = 500;
SET GLOBAL wait_timeout = 60;
SET GLOBAL interactive_timeout = 60;
注意:wait_timeout 对已经建立的连接不生效,只对新连接生效;
要彻底清除旧连接,还是建议维护窗口内重启一次。
连接数调多大才合适
不要盲目设置成几千,每个连接都会占用线程栈和内存。
MySQL 5.7 的线程池并非默认开启,连接数越多,内存占用越高。
粗略估算:每个连接可能占用几百 KB 到几 MB 内存,再加上 InnoDB 缓冲池,所以 max_connections 要结合服务器内存来定。
如果 2GB 内存的云服务器,建议先设成 300 左右,观察 Threads_connected 是否有增长趋势。
同时检查系统 ulimit:
ulimit -n
如果这个值小于 max_connections,连接数到了系统层面也会被拒绝。
可以临时调大:
ulimit -n 65535
永久生效要写在 /etc/security/limits.conf 里,例如:
mysql soft nofile 65535
mysql hard nofile 65535
其他隐藏的连接拒绝原因
连接数调大了仍然报错,还要检查这几个方向:
bind-address配置:如果/etc/my.cnf里写成了bind-address = 127.0.0.1,外部连接会被直接拒绝。改成0.0.0.0或注释掉。skip-networking:如果开启了这项,MySQL 只允许本机通过 socket 连接,任何 TCP 请求都会失败。检查配置里是不是有skip-networking。- 防火墙:CentOS 7 以上执行
firewall-cmd --list-all,确认 3306 端口已放行。 - 用户权限:
SELECT user, host FROM mysql.user;确认应用账号的 host 包含了目标 IP,而不是只有localhost。
调优后的验证方法
重启或动态修改后,重新查看状态:
SHOW STATUS LIKE 'Threads_connected';
SHOW STATUS LIKE 'Max_used_connections';
SHOW STATUS LIKE 'Aborted_connects';
Max_used_connections 是历史最高连接数,如果这个值经常接近 max_connections,说明调优幅度还不够。
建议保留一个监控脚本,定时记录这两个值:
mysql -uroot -p -e "SHOW STATUS LIKE 'Threads_connected';" >> /tmp/mysql_conn.log
持续观察几天,如果 Threads_connected 稳定在安全水位,同时业务端不再报“连接拒绝”,就说明 wait_timeout 和连接数配置已经匹配当前负载。
调优后如果问题反复,建议把慢查询日志打开,看看是不是有大量查询卡死导致连接长期占用。
毕竟连接数只是表象,真正要解决的是背后积压的 SQL。