Appearance
生产问题:MySQL 连接数打满时怎么排查
MySQL 连接问题有两种很常见的现场:
- 连接数打满
- 因连接错误过多被封锁
它们看起来都像“数据库连不上”,但根因往往不一样。
线上最典型的表现一般是:
- 应用大量报
too many connections - 数据库 RT 明显升高
- 应用线程堆在获取连接上
- 某些接口雪崩,重试后问题更严重
先说结论
排查 MySQL 连接问题时,优先看四件事:
- 连接池配置是不是合理
- 有没有慢 SQL 长时间占着连接
- 事务是不是没及时提交或释放
- 是否存在错误重试把数据库打爆
更进一步说,连接打满通常不是“连接数量本身不够”,而是:
- 连接占用时间太长
- 连接释放太慢
- 同一时间段请求量和重试量都放大了
- 数据库在下游最慢环节上承受了额外压力
一、一个典型错误
如果出现:
Host xxx is blocked because of many connection errors
可以先解除封锁:
bash
flush hosts;但这个动作只是解封,不是根治。
真正还要继续查:
- 为什么短时间内出现大量连接错误
这类错误更像“症状清理”,不是问题修复。
二、连接数打满时常见根因
- 慢 SQL 太多
- 下游事务执行过长
- 连接池太小
- 程序拿到连接后没及时释放
- 故障时应用侧疯狂重试
实际线上更常见的根因画像通常是:
1. 慢 SQL 把连接长期占住
比如没走索引、排序分页过重、大表扫描,最终表现成连接都在忙,但真正业务吞吐却没上去。
2. 长事务或锁等待
应用已经拿到连接,但因为事务迟迟不提交、锁冲突严重,连接长时间不释放。
3. 连接池本身已经被业务线程打满
这时就要看是流量真的暴涨了,还是应用退化导致单位请求占用连接时间更久。
4. 故障时重试风暴
数据库已经慢了,应用、网关、任务系统还在同时重试,最终把本来局部问题放大成连接池雪崩。
三、排查顺序
更实用的顺序通常是:
- 先看连接池监控
- 再看数据库当前活跃连接
- 看有没有长事务和慢 SQL
- 看应用日志有没有超时和重试放大
如果线上比较紧急,我通常会再加一个判断:
- 先分清是“连接建立不上”,还是“连接借不到”
这两种看起来都像“数据库不可用”,但根因完全不同:
- 建立不上,更像网络、认证、连接错误或数据库已经拒绝新连接
- 借不到,更像连接池耗尽、SQL 太慢、事务太长
四、一个常见误区
很多人第一反应是直接把连接池调大。
这有时能缓一阵,但如果根因是:
- SQL 太慢
- 事务太长
- 代码没释放资源
那只是把问题往后拖。
还有两个很常见的误区:
1. 只看数据库,不看应用重试
很多时候数据库只是已经变慢,真正把连接打满的是上层在错误重试。
2. 只看总连接数,不看活跃连接在做什么
真正有价值的是分清:
- 哪些连接在执行 SQL
- 哪些连接在锁等待
- 哪些连接空闲但被长事务占住
五、一个更现场化的处理顺序
如果线上已经大量报错,我更建议按这个顺序处理:
- 先限流或关闭明显的重试风暴,避免继续放大。
- 看连接池借用等待是否在急剧上升。
- 看数据库活跃连接里是否有慢 SQL、长事务、锁等待。
- 看最近是否有发版、批处理、定时任务、报表查询一起打上来。
- 最后再决定是优化 SQL、回滚任务、降级接口还是临时调大连接上限。
这个顺序更适合真实生产环境,因为连接打满往往不是单点问题,而是一整条请求链路在退化。
一句话总结
MySQL 连接数问题本质上很少只是“连接不够”,更多时候是连接被用得太久、释放得太慢,或者错误重试把压力放大了。先把连接占用时间、慢 SQL、长事务和重试风暴这几条线看清,问题通常就能更快收敛。