PostgreSQL 报连接数超限,连接池明明只设了 10
连接池上限属于单个池,PostgreSQL 看到的是所有进程与任务的总连接。先统计来源,再查重复池和长事务。
应用连接池只设了 10,PostgreSQL 却报 sorry, too many clients already。数据库接收的是所有应用、任务、管理工具和部署副本的连接,不能只看一个进程里的池上限。
先保留有效管理连接,读取实例统计,再改配置。只把 max_connections 调大可能暂时减轻症状,却没有解释连接从哪里来。
数据库拒绝连接,还是应用在等空闲连接
服务器拒绝新客户端,与应用等待池内空闲连接超时不同。一个遵守上限的池不会因为忘记归还就无限突破自己的最大值,但会让后续请求一直等待。两种问题可以同时出现,需要看原始错误和发生位置。
用有相应权限的管理连接读取:
SHOW max_connections;
SHOW superuser_reserved_connections;
SELECT datname, usename, application_name, client_addr,
state, count(*) AS connections
FROM pg_stat_activity
WHERE backend_type = 'client backend'
GROUP BY datname, usename, application_name, client_addr, state
ORDER BY connections DESC;
连接限制属于整个 PostgreSQL 实例,不只属于当前逻辑数据库。先统计全局,再按应用追踪;统计详情有权限边界,看不到其他会话的部分字段,不代表那些会话不存在。
PostgreSQL 16 及以上还可能设置 reserved_connections。普通应用的预算要扣除相应保留区与维护余量,不能直接分配整个 max_connections。老版本不执行不支持的参数查询。参数范围见 PostgreSQL 连接配置。
按进程数计算潜在上限
举例:8 个进程,各有两个上限为 10 的池,潜在连接容量为 160,尚未算其他任务。池可能按需建立连接,这不表示一启动就有 160 个真实连接,但必须把这个上限纳入预算。
盘点容器副本、worker 数、每个 worker 的池数和后台任务。滚动部署时旧新进程并存,也可能短时增加连接。近期增加了应用副本,就重新分配各副本的池大小,而不是每个副本都按数据库总量配置。
代码中检查池是不是在进程级初始化,还是每次请求都 new Pool();还有直接建立客户端的路径是否绕过池。把 application_name 设置成可区分的服务标识,统计会更容易对应实际来源。
显式借出的客户端一定归还
以 node-postgres 为例,独立单条查询可以用 pool.query() 自动借还连接。显式取客户端时,让成功与失败路径都执行归还:
// pool 已在当前进程创建
const client = await pool.connect();
try {
const result = await client.query('SELECT 1');
// 使用 result
} finally {
client.release();
}
事务的 BEGIN、业务语句与 COMMIT 必须使用同一个客户端;不能把事务中后续操作随意交给 pool.query()。错误时处理回滚,并按连接状态决定是否销毁损坏客户端。长驻服务在关闭进程时结束池,不在每次请求后 pool.end()。
继续看持有时间和等待:
SELECT pid, usename, application_name, state,
now() - xact_start AS transaction_age,
now() - query_start AS query_age,
wait_event_type, wait_event
FROM pg_stat_activity
WHERE backend_type = 'client backend'
AND pid <> pg_backend_pid()
ORDER BY xact_start NULLS LAST, query_start NULLS LAST;
idle 可以是池保留的正常空闲连接;idle in transaction 则需要检查遗漏提交、回滚或事务内等待外部请求。不能仅按会话年龄批量终止,它可能仍在处理重要任务。
先控制来源,再调整容量
确认重复池、长事务或归还遗漏时,修复对应路径。非必要任务降低并发,池上限按总预算配置;同时观察取连接等待、请求延迟和积压,降低连接数也可能增加等待。
确定确有容量需求以后,再评估参数与硬件。max_connections 的修改涉及资源预算且通常需要重启数据库,安排维护窗口与回退;连接代理也需核对事务和会话状态兼容,不能当作无条件替换。
日志与负载确实显示现有内存不足时,比较VPS 内存配置与应用总预算。重复建池或长事务没有解决,单纯加内存仍可能再次触及限制。
确认连接来源合理、实际内存与业务压力仍不足时,再按数据库、应用副本和维护余量增配。可比较 Evoxt 的内存规格,或查看 ECS 的数据库部署配置,先试同一份数据与合理连接预算。规格按正常负载决定,不能直接把某个连接数换算成固定 GB;重复建池与长事务必须先修。
测试时要让正常业务、后台任务和新旧部署副本同时运行,观察连接趋势并确认维护通道仍可用。原失败请求恢复、池等待下降,以及连接数量能与实例预算对应,才说明这次修改解决了相应问题;低负载暂时不报错不足以证明高峰问题已解决。




