90%的“Too many connections”错误源于连接泄漏而非max_connections设置过低;应先用socket直连检查Threads_connected与Threads_running,定位Sleep连接来源,再通过调整wait_timeout/interactive_timeout和精准KILL清理,而非直接调高max_connections。

别急着改 max_connections,90% 的线上 Too many connections 报错,根本不是上限低,而是连接卡着不放——你还能用 root 本地登录,就说明 MySQL 进程活着,只是“门被堵死了”。
先确认是不是真连满了
用 socket 直连(避免走网络层加重负担)执行三行命令:
-
SHOW VARIABLES LIKE 'max_connections';—— 看上限,MySQL 5.7/8.0 默认是 151 -
SHOW STATUS LIKE 'Threads_connected';—— 看当前连接数,如果 ≥ 150,新连接就会被拒 -
SHOW STATUS LIKE 'Threads_running';—— 看真正干活的线程数;如果只有个位数(比如 2 或 5),而Threads_connected是 149,那基本全是 Sleep 连接在占坑
注意:Threads_connected 接近上限 ≠ 必须扩容,它只说明“连接没释放”,而不是“业务并发高”。很多团队查完就去改配置,结果几小时后又爆——泄漏还在继续。
快速定位谁在占着不放
重点不是“有多少连接”,而是“谁建的、从哪来、卡了多久”:
- 执行
SELECT USER, HOST, COUNT(*) FROM information_schema.PROCESSLIST GROUP BY USER, HOST ORDER BY COUNT(*) DESC;—— 按用户+IP 统计连接数,一眼看出异常来源(比如某个 PHP 脚本 IP 占了 80 个连接) - 执行
SHOW PROCESSLIST;—— 关注Command = 'Sleep'且Time > 300的行(空闲超 5 分钟),这些大概率是泄漏连接 - 特别留意
State列:如果卡在sending data、Locked、Waiting for table metadata lock,说明不是泄漏,而是 SQL 或锁阻塞了连接释放
云数据库(如阿里云 RDS)可能禁用 KILL 普通连接,得走控制台或专用管理端口;自建库则可继续操作。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
应急清理:别硬 kill,先缩超时再精准终止
直接 KILL 所有 Sleep 连接风险高——监控、ETL 工具等长连接也会被干掉。稳妥做法分两步:
- 先收紧超时,让闲置连接自动断开:
SET GLOBAL wait_timeout = 120;(非交互式连接,2 分钟空闲即断)SET GLOBAL interactive_timeout = 180;(交互式连接,3 分钟)
注意:这两个值只影响新建立的连接,已存在的 Sleep 连接仍按旧 timeout 计时 - 再对确认无用的连接逐个
KILL:
查出 ID:SELECT ID, USER, HOST, TIME FROM information_schema.PROCESSLIST WHERE COMMAND = 'Sleep' AND TIME > 300;
逐个执行:KILL 12345;(填具体 ID)
别用KILL QUERY,它只停语句,连接还占着
如果连 mysqladmin 都无法执行(比如 mysqld_safe 启动的实例),可用 kill -TERM $(pgrep -f "mysqld") 发送安全退出信号,MySQL 会先刷盘再关,不丢数据。
为什么 SET GLOBAL max_connections 常常不生效
执行 SET GLOBAL max_connections = 1000; 后查还是 151?不是命令错了,是被系统级限制拦住了:
- 运行
ulimit -n,若返回 1024,而你想设 2000,MySQL 启动时会自动向下取整到 1024 - systemd 管理的服务必须在
/usr/lib/systemd/system/mysqld.service的[Service]段加:LimitNOFILE=65536LimitNPROC=65536
然后执行systemctl --system daemon-reload && systemctl restart mysqld - MySQL 8.0.22+ 若已用
SET PERSIST写入mysqld-auto.cnf,该文件优先级高于my.cnf,改my.cnf不覆盖
最易被忽略的一点:Docker 容器里没配 --ulimit nofile=65536:65536,光改 MySQL 配置毫无意义——容器内 ulimit 仍是默认值。










