先确认threads_connected是否接近max_connections,若远低于后者却报错,则多因应用连接池配置不当或max_user_connections限制;再查show processlist中sleep超300秒、locked或connect状态异常连接,并同步检查ulimit与连接池参数。

连接数打满时,先看 Threads_connected 和 max_connections 是否真接近
别一看到报错就改配置。先连上 MySQL 执行:SHOW GLOBAL STATUS LIKE 'Threads_connected';SHOW VARIABLES LIKE 'max_connections';
如果 Threads_connected 比如是 148,而 max_connections 是 151,那确实是打满了;但如果只是 80,却报 Too many connections,大概率是应用侧连接池没配好,或者有 root 用户被限制了 max_user_connections——这个值默认为 0(不限),但有些 RDS 或安全加固后会设成很小的数,得查:SELECT user, host, max_connections FROM mysql.user;
查 SHOW PROCESSLIST 时重点关注三类连接
执行 SHOW FULL PROCESSLIST; 后,盯住这几类异常连接:
-
State是Sleep但Time超过 300 秒(5 分钟)的:很可能是应用获取连接后没 close,或连接池空闲回收时间设得太长 -
State是Locked、Waiting for table metadata lock或长时间卡在Updating的:背后大概率是慢查询、未提交事务或 DDL 操作阻塞了其他连接 -
Command是Connect但Time为 0 或极小:说明大量新连接正在尝试建立,但被拒之门外,这是“连接风暴”信号,不是数据库本身慢,而是上游在疯狂重试
应用层连接池必须设 maxWait 和 minEvictableIdleTimeMillis
光设 maxActive(或 maximumPoolSize)不够,容易把 DB 打爆。关键参数要配套:
-
maxWait(Druid)或connection-timeout(HikariCP)必须设,比如 3000ms,否则线程会无限等连接,拖垮整个服务 -
minEvictableIdleTimeMillis(Druid)或idle-timeout(HikariCP)建议设为 60000(60 秒),防止空闲连接长期占着不放 -
removeAbandonedOnBorrow(Druid)或leak-detection-threshold(HikariCP)务必打开,能主动回收疑似泄漏的连接
注意:这些参数值不是越大越好。比如 idle-timeout 设成 30 分钟,等于默许连接池里一堆“僵尸连接”挂半天,DB 端早把它们当失效连接踢了,但池子还留着,最终导致连接数虚高。
max_connections 不是调大就安全,得看系统资源和文件描述符上限
MySQL 默认 max_connections = 151,很多团队直接改成 2000,结果发现 mysqld 启动失败或运行中频繁报 Can't create thread。这是因为:
- 每个连接至少消耗 256KB 内存(实际可能翻倍),2000 连接 ≈ 500MB+,超出物理内存就触发 swap,性能断崖下跌
- Linux 默认
ulimit -n是 1024,MySQL 进程打开的文件数(含 socket、表、日志)超过这个值就会失败,必须同步调大:echo "* soft nofile 65536" >> /etc/security/limits.conf - RDS 类产品(如阿里云、腾讯云)对
max_connections有硬上限,且和实例规格强绑定,盲目调大会被拒绝或自动回滚
真正该做的,是让每个连接更“短命”、更“轻量”,而不是堆数量。连接耗尽本质是释放速度跟不上创建速度,堵点往往不在数据库,而在应用代码里漏掉的 close() 或事务里嵌套的 HTTP 调用。











