MySQL连接数耗尽:1040错误排查

ERROR 1040: Too many connections 表示连接请求遇到了服务器连接数限制。它与密码错误、端口不通不同;先降低连接压力,再找出谁在占用,通常比立刻重启数据库更有利于恢复。

适用范围:MySQL 8.0、8.4。下文 SQL 在已有的、获授权的数据库会话执行。没有可用会话时,应先从应用端止住连接增长,或联系数据库管理员使用已配置的管理通道;不要假设一定还有可用的额外管理员连接。

先让连接需求降下来

暂停非关键批处理,限制无限重试和瞬间并发,检查是否刚扩容了应用实例或调大工作进程数。连接池上限往往是“每个进程一份”:实例数乘进程数再乘池上限,才接近应用可能占用的总量,还要加定时任务、监控及人工维护需求。

优先调整出问题的应用池和重试策略,分批生效,避免所有实例同时重启重连。记录原值便于回退;回退也要控制节奏,不能重新制造连接洪峰。不要先批量杀掉所有空闲连接。

用四个指标判断,而非只看一张截图

SELECT VERSION();
SHOW GLOBAL VARIABLES
WHERE Variable_name IN ('max_connections','wait_timeout','interactive_timeout');
SHOW GLOBAL STATUS
WHERE Variable_name IN ('Threads_connected','Threads_running',
                       'Max_used_connections','Connection_errors_max_connections','Uptime');
SHOW PROCESSLIST;

SHOW GLOBAL STATUS 与 SHOW GLOBAL VARIABLES 本身不要求特殊权限,但必须已经成功连接。SHOW PROCESSLIST 有 PROCESS 权限才能看全部线程,否则普通账户通常只能看到自己的线程,不能据此断言全库没有其他连接。输出可能带 SQL、账户和来源地址,分享前脱敏。

指标 如何读
Threads_connected 当前打开的连接,包含空闲连接
Threads_running 当前不是睡眠状态的线程,不等于正在消耗 CPU 的查询数
Max_used_connections 峰值记录,不能当成当前占用
Connection_errors_max_connections 因达到连接上限而被拒绝的累计次数,重点看是否继续增长

间隔十几秒再查一次全局状态,同时记录业务流量与 Uptime。计数减少或服务器刚重启时,不宜直接与之前相减。连接数接近上限而非睡眠线程很少,优先看池总量、空闲连接和泄漏;两者都高,还需检查慢查询、锁等待及请求堆积。

Sleep 多不等于可以全部断开

Sleep 只说明连接当前没有执行命令,连接池保留空闲连接本来就可能正常;它也不能证明不存在尚未提交的事务。结合账户、来源、持续时间、应用池监控以及事务情况,识别哪些连接来自异常实例。贸然断开会让应用报错,涉及事务时还可能触发回滚。

检查异常分支是否归还连接、请求结束是否清理资源、事务是否及时提交或回滚。若请求变慢导致连接长期借出,先解决慢 SQL 或锁等待。单纯缩短 wait_timeout 不会修好正在占用的连接,反而可能让连接池借出已失效连接;超时策略要和池的校验、空闲回收机制一起调整。

何时才考虑提高上限

确认没有泄漏、池总量合理且业务确有需求后,再评估内存、文件描述符和负载余量。不要复制一个很大的 max_connections 数字:允许更多连接,也可能扩大资源竞争。重启会中断现有会话、影响事务并丢失部分现场,不能替代定位。

若确需调整,先记录原值与实际配置来源。SET GLOBAL 修改运行时值,单独使用不会将设置写入持久配置;SET PERSIST 同时修改运行时并写入持久设置。修改全局变量需相应管理权限。RESET PERSIST 只移除持久设置,不会恢复当前运行时值,回退要分别处理两部分。

恢复的判断是:正常业务流量下,连接拒绝计数不再增长,连接池等待和接口延迟回落,连接数保有余量。至少观察一个有代表性的业务时段,避免把低峰暂时正常当成问题已经消失。

延伸阅读