直接答案:too many clients already 表示 PostgreSQL 可用连接槽位已经耗尽。先通过保留的管理员连接或本机控制台查询 pg_stat_activity,按 application_name、client_addr、用户、数据库和 state 统计,区分真实并发、连接池总上限叠加、连接泄漏、长期 idle in transaction 与慢查询。优先限流、回收已确认无效连接、修池与事务边界;仅提高 max_connections 会增加共享内存和每连接开销,可能把连接错误变成内存或上下文切换问题。
本文适合应用突发无法连库、日志出现 FATAL too many clients 或连接池超时。若是单个角色达到平台/代理限额、或托管数据库通过代理端点限制,还要查对应产品指标,不能只改数据库全局参数。
本文按 2026 年 9 月可查的官方文档核对。示例命令以只读取证为主;凡涉及删除、覆盖、重启、权限、网络或数据库参数的动作,都应先确认操作对象、备份、维护窗口和带外恢复入口。不同发行版与软件版本的路径可能不同,必须先查询实际配置再改。
先用证据判断故障在哪一层
| 现象或检查点 | 它能说明什么 | 直接证据 | 不要误判为 |
|---|---|---|---|
| active连接接近上限 | 真实并发或慢查询占用 | pg_stat_activity、等待事件与QPS | 空闲连接太多 |
| idle连接大量长期存在 | 池最小/最大配置或泄漏 | 应用名、客户端与连接年龄 | 数据库CPU瓶颈 |
| idle in transaction | 事务未提交并持有资源 | xact_start、query与应用请求 | 普通池空闲 |
| 多个实例各自大连接池 | 总池上限乘法超过数据库预算 | 实例数×pool max与滚动发布重叠 | max_connections太小 |
| 重启应用后暂时恢复 | 连接由应用释放但根因未修 | 恢复前后连接曲线 | 数据库已永久修复 |
这张表的用法不是“看到一个关键词就改一个参数”,而是把客户端、DNS或边缘、Web 代理、应用、数据层依次分开。至少保留故障时间、完整 URL、状态码、关键响应头、同一时刻的服务日志和一份正常样本。只有时间能够对齐,才能判断两个现象是否属于同一次故障。
六步排查与修复顺序
1. 保留应急管理员入口
确认 superuser_reserved_connections/保留槽位和本机控制台,避免所有槽位被普通应用占满。若已经无法登录,先限流或停止造成连接风暴的单一应用实例,避免重启数据库造成更大写入中断。
2. 按来源与状态分解连接
查询 pg_stat_activity,按数据库、用户、application_name、client_addr 和 state 计数,并记录 backend_start、xact_start、query_start 与 wait_event。先得到完整分布,再决定清理对象。
3. 计算所有池的总预算
将每个应用实例的 pool max、最小空闲、后台任务、管理工具、迁移任务、监控和滚动发布临时双实例相加。数据库连接预算要小于 max_connections 减去维护与复制余量,不能只看单个 Pod。
4. 处理泄漏、长事务与慢请求
修复未关闭连接、异常路径和事务边界;idle in transaction 会持有快照/锁并阻碍维护。终止连接前核对 PID、用户、事务和写入,优先取消查询、让应用优雅释放,避免随意终止关键事务。
5. 引入或调整连接池
应用池要设置获取超时、最大生命周期、空闲回收、健康检查和 application_name。大量短连接可评估 PgBouncer 等代理,但 transaction pooling 对 session 状态、临时表和 prepared statements 有兼容边界,需测试。
6. 谨慎评估 max_connections
提高上限前测每连接内存、work_mem并发、共享内存、CPU和上下文切换;该参数需要重启。更高连接数不等于更高吞吐,常见目标是用较少数据库连接服务更多应用请求。
可复制的只读取证命令
以下命令中的域名、服务名、路径和时间范围要替换为自己的真实值。先执行查询命令并保存原始输出;不要把“命令能运行”误当成“业务已恢复”。
text
sudo -u postgres psql -Atc "SHOW max_connections; SHOW superuser_reserved_connections;"
sudo -u postgres psql -c "SELECT datname,usename,application_name,client_addr,state,count(*) FROM pg_stat_activity GROUP BY 1,2,3,4,5 ORDER BY count(*) DESC;"
sudo -u postgres psql -c "SELECT pid,usename,application_name,state,now()-xact_start AS xact_age,wait_event_type,wait_event,left(query,120) FROM pg_stat_activity WHERE xact_start IS NOT NULL ORDER BY xact_start;"
sudo -u postgres psql -c "SELECT state,count(*),max(now()-state_change) AS oldest FROM pg_stat_activity GROUP BY state;"
ss -ntp | grep ':5432' | head -n 80
sudo -u postgres psql -Atc "SHOW max_connections; SHOW superuser_reserved_connections;":读取全局上限和管理员保留槽位sudo -u postgres psql -c "SELECT datname,usename,application_name,client_addr,state,count(*) FROM pg_stat_activity GROUP BY 1,2,3,4,5 ORDER BY count(*) DESC;":按来源和状态统计连接分布sudo -u postgres psql -c "SELECT pid,usename,application_name,state,now()-xact_start AS xact_age,wait_event_type,wait_event,left(query,120) FROM pg_stat_activity WHERE xact_start IS NOT NULL ORDER BY xact_start;":查长事务和等待,查询文本可能含敏感信息需脱敏sudo -u postgres psql -c "SELECT state,count(*),max(now()-state_change) AS oldest FROM pg_stat_activity GROUP BY state;":概览各状态数量与最老状态年龄ss -ntp | grep ':5432' | head -n 80:从操作系统侧抽样连接端点,与数据库视图交叉验证
如命令输出包含公网 IP、用户名、Cookie、令牌、数据库连接串或客户数据,分享工单前先脱敏。对比时保留时间戳、时区和命令本身,否则后来无法复现同一观察条件。
五个最容易扩大故障的误区
- 直接把max_connections翻十倍:会增加内存与调度压力,吞吐未必提升。
- 终止所有idle连接:池会立即重建,且普通idle不等于泄漏;要看年龄与池策略。
- 重启数据库清连接:会中断所有事务和复制,只把根因清零后重新积累。
- 只算一个应用实例的池:多副本、任务和滚动发布会把连接上限相乘。
- 把idle in transaction当普通idle:前者仍持有事务资源,影响锁、vacuum和复制。
变更、回滚与数据边界
连接池变更要保留旧配置和分批发布,若等待时间、错误或数据库CPU上升,恢复上一池大小并限制新实例扩张。max_connections 变更需要重启,执行前备份配置、确认内存和复制节点一致;回滚同样需要窗口。终止后端无法撤销已回滚事务,对写业务要核对客户端重试和幂等。
如果只能先恢复服务、还不能确认根因,应把措施标记为“临时缓解”,例如限流、摘除单节点、切回上一配置或临时绕过一层代理。恢复后仍要在受控环境复现原因,并验证同类故障不会在下一次重启、发布或高峰重新出现。
统一验收清单
- [ ] 保留管理员连接可用
- [ ] 连接按应用、客户端、用户和状态可解释
- [ ] 所有实例与任务的池上限总和已计算
- [ ] 长事务和泄漏有明确责任方
- [ ] 连接池具备超时、回收和application_name
- [ ] 关键写请求重试具备幂等
- [ ] 高峰下连接未触顶且等待可控
- [ ] 数据库内存、CPU与尾延迟未因提高上限恶化
验收必须同时覆盖机器内部和真实外部路径。首页返回 200 不能证明上传、长连接、登录、数据库写入或移动端都正常;同样,控制台显示“运行中”也不能证明应用已能处理请求。至少选一个正常请求、一个边界请求和一个失败请求,记录预期与实际结果。
相关内容与隔离测试入口
建议先阅读MySQL连接数过多、云服务器内存怎么选、Spring Boot服务器配置,把本问题放回完整请求链路。若生产环境不适合直接试验,可查看美国弹性云服务器的当前规格与库存,搭建与生产隔离的复现环境;测试机不能替代生产备份,价格、库存和可选配置以实时产品页为准。
常见问题
idle连接是不是都应该关闭?
不是。池保留少量空闲连接可降低建连成本;问题在总量、年龄、预算和是否按策略回收。
idle in transaction 为什么危险?
事务仍开放,可能持有锁和旧快照,阻碍vacuum并增加膨胀。应修应用事务边界。
max_connections 越高吞吐越大吗?
通常不是。大量并发会争抢CPU、内存和I/O,合适连接池常比无限连接更稳定。
PgBouncer 能直接解决吗?
它可复用连接,但池模式与应用会话语义有兼容条件,也不能修慢SQL和长事务。
为什么滚动发布时更容易爆连接?
新旧实例短时间并存,各自建立最小/最大池,总连接可能瞬间接近两倍。发布预算必须计入。