PostgreSQL连接报错too many clients怎么办

文章导读
“too many clients” 不是网络不通,也不是账号密码错了,而是 PostgreSQL 已经不允许新的客户端连接进来。此时继续重试、重启应用或加连接池参数,通常都不会让报错消失,真正要做的是先判断连接被谁占满,再决定是清理、限流还是调整上限。本文提供一个可执行的判断路径:先确认场景,再按顺序处理,最后验证结果,并说明哪些边界不能忽略。
📋 目录
  1. Ⅰ 先确认当前场景和目标
  2. Ⅱ 按这个顺序处理
  3. Ⅲ 改完后怎么验证
  4. Ⅳ 容易忽略的边界
A A

“too many clients” 不是网络不通,也不是账号密码错了,而是 PostgreSQL 已经不允许新的客户端连接进来。此时继续重试、重启应用或加连接池参数,通常都不会让报错消失,真正要做的是先判断连接被谁占满,再决定是清理、限流还是调整上限。本文提供一个可执行的判断路径:先确认场景,再按顺序处理,最后验证结果,并说明哪些边界不能忽略。

遇到 “too many clients” 时,先不要调大 max_connections。应先在还能连上的会话里查询 pg_stat_activity,确认占用连接的是业务连接池、空闲事务还是长查询,并核对 max_connections 与保留连接参数。处理顺序通常是:清理明显异常的会话、修复连接泄漏、再评估是否调整上限。调大上限只是把压力推给内存和调度,需要结合机器规格确认,且不能替代连接池治理。

先确认当前场景和目标

这个问题成立的前提是:报错来自 PostgreSQL 服务端,而不是应用侧连接池自己的上限。应用报 “too many clients already” 一般说明服务端拒绝新建连接;如果只是某个连接池提示池已满,而数据库端还有余量,那问题在应用侧排队策略,处理方式完全不同。

动手前先确认几件事:

  • 报错原文和出现位置:是应用日志、驱动异常,还是 psql 直接连接时报的。psql 也连不上,说明服务端连接槽位确实耗尽;只有某个应用报错,则可能是该应用池配得过小或泄漏。
  • 当前 max_connections 和 superuser_reserved_connections 的实际值。保留连接数决定超级用户还能挤进去几个,排查时通常靠它登录。
  • 是否有连接池中间件(如 PgBouncer)在数据库前面。有池的话,数据库侧连接数应相对稳定,暴涨往往意味着池配置或会话模式有问题。
  • 业务是否处于发布、批量任务、报表导出等高峰时段,这决定是临时峰值还是持续性泄漏。

目标也要先定清楚:是撑过当前故障让业务恢复,还是降低长期连接占用。前者允许先清理会话止血,后者必须动连接池和代码,两者不要混为一谈。

按这个顺序处理

第一步,用超级用户或保留连接登录,观察连接分布。下面这条查询按状态和来源聚合,先看整体结构,不要一上来就逐个杀会话:

PostgreSQL连接报错too many clients怎么办
SELECT state, count(*) AS conns,
       max(now() - state_change) AS max_idle
FROM pg_stat_activity
GROUP BY state
ORDER BY conns DESC;

如果 idle 占比很高,通常是应用拿了连接不释放,或者连接池的 idle 超时设置过长;如果 idle in transaction 明显,说明有事务开着却不在干活,这类会话既占连接又可能持有锁,优先处理;如果是 active 且持续增长,则要看是不是慢查询或并发突增。

第二步,定位具体来源。按应用名、用户、客户端地址分组,找出是谁占的:

SELECT application_name, usename, client_addr,
       state, count(*) AS conns
FROM pg_stat_activity
GROUP BY application_name, usename, client_addr, state
ORDER BY conns DESC
LIMIT 20;

第三步,对确认异常的会话做定向清理。只终止明确属于泄漏或卡死的会话,不要整批杀,避免影响正常业务:

SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE state = 'idle in transaction'
  AND now() - state_change > interval '10 minutes'
  AND pid <> pg_backend_pid();

时间阈值要结合业务事务的正常耗时来定,不能照搬。执行前先用同样的 WHERE 条件 SELECT 一遍,确认要终止的列表符合预期。

第四步,回到根因。应用侧检查连接是否在异常分支里没有 close 或归还池;连接池的最大连接数乘以实例数,是否已经超过数据库的 max_connections;有没有把连接池配置成“每个请求新建连接”。这些问题不修,清理完很快会再次占满。

PostgreSQL连接报错too many clients怎么办

第五步,再评估是否调整服务端参数。调整 max_connections 需要重启或 reload 才能生效,并且每个连接都会占用一定内存,连接数越高,内存和调度压力越大。通常建议先通过连接池把数据库侧并发收敛到一个可控范围,再考虑小幅上调,而不是直接把上限翻倍。

改完后怎么验证

清理或改配置后,不要只看“当前能连上”就结束。可以先做几个观察动作:

  • 重复执行按 state 聚合的查询,确认 idle in transaction 的数量回落到接近零,总连接数低于 max_connections 的八成左右,留出余量应对突发。
  • 用普通业务账号新建一次连接,确认不再报 too many clients;同时确认原有业务连接没有被误杀。
  • 观察一段时间内的连接数曲线,看是否呈锯齿状反复冲高。如果清理后短时间内又涨回上限,说明泄漏或池配置问题仍在。
  • 检查数据库日志中是否还有连接被拒的记录,以及是否有 FATAL 级别的认证或资源报错。

如果调整过参数,用 SHOW max_connections; 确认实际生效值,并确认应用侧连接池上限与数据库上限之间的倍数关系符合预期。

容易忽略的边界

第一,调大 max_connections 不是无损操作。它受内存约束,连接数过高会加剧上下文切换,某些场景下反而让整体响应变慢。在没有确认内存余量和实际并发需求前,不建议大幅上调。

PostgreSQL连接报错too many clients怎么办

第二,superuser_reserved_connections 是排查时的保命通道,不建议为了腾出连接而把它改成 0,否则故障时将无法用管理员身份登录处理。

第三,托管数据库通常对 max_connections 有实例规格绑定,可调范围有限,且修改可能需要重启。云上环境要先确认控制台允许的参数范围,不要直接照搬自建库的经验。

第四,终止会话属于有损操作。被终止的会话对应的事务会回滚,长事务回滚可能耗时并占用资源。对承载写入的会话执行前,应确认可以接受该事务丢失。

第五,PgBouncer 的 transaction 模式能显著降低数据库侧连接数,但它会改变会话级特性(如会话级临时表、部分 SET 行为)的语义,迁移前需要结合应用用法确认兼容性。若无法确认,回退到 session 模式或维持原状,比贸然切换更稳妥。