PostgreSQL 的 max_connections 参数决定了服务器允许的最大并发客户端连接数。默认值是 100,这个数字在很多小型开发场景里够用,一旦业务增长、微服务实例变多,很容易出现连接不够的情况。但要警惕的是,直接把这个参数调大并不是解决连接瓶颈的正确思路,因为每个连接在 PostgreSQL 内部都对应一个独立的后端进程,连接数越多,内存和调度成本上升得越快。

当客户端发起连接时,PostgreSQL 主进程 postmaster 会为每个连接派生一个子进程,也就是 backend process。这个进程负责执行 SQL、维护事务状态以及缓存部分数据。它不像某些数据库那样采用线程模型,而是进程模型,因此每个连接都有独立的内存空间。一个空闲连接虽然不执行查询,依然会占用基础内存,通常在几 MB 到十几 MB 不等,具体取决于编译选项、共享库加载情况和 work_mem 等参数。如果再加上每个后端进程可能分配的工作内存,连接数过高会迅速耗尽物理内存,触发操作系统的 OOM Killer,导致数据库实例被强制杀死。
可以用下面的 SQL 查看当前实例允许的连接数和实际已使用的连接数:
SHOW max_connections;
SELECT count(*) AS total_connections,
count(*) FILTER (WHERE state = 'active') AS active_queries,
count(*) FILTER (WHERE state = 'idle') AS idle_connections
FROM pg_stat_activity;
需要注意的是,max_connections 的修改需要重启数据库才能生效,因为它属于 postmaster 级别的参数。执行 ALTER SYSTEM SET max_connections = '300'; 后只是写入配置文件,必须通过 pg_ctl restart 或服务管理命令重启实例才会真正应用。这也意味着在生产环境调整这个参数不能像 work_mem 那样动态生效,必须安排维护窗口。
如何评估合理值:从业务并发和硬件资源出发
评估 max_connections 的合理值,首先要区分两个概念:总连接数和活跃事务数。很多应用框架的连接池默认会创建几十甚至上百个连接,但这些连接大部分时间可能处于 idle 状态。真正给数据库带来压力的,是同一时刻正在执行 SQL 的活跃连接数。如果业务高峰只有 30 个请求同时访问数据库,那么把 max_connections 设置为 500 并不会让这 30 个请求跑得更快,反而会让后端的 470 个空闲连接白白占用内存和进程调度资源。
一个可落地的估算思路是:先通过监控获得高峰期的活跃连接数,再预留 20% 到 30% 的余量,同时考虑管理任务、备份任务和超级用户保留连接。假设高峰期活跃连接数为 80,那么设置 120 到 150 通常足够。更保守的做法是引入连接池,比如 PgBouncer,让应用先连接到连接池,再由连接池复用少量的实际数据库连接。这样数据库侧的 max_connections 可以大幅降低,例如只设置 100 到 200,就能支撑数百个应用线程。
从硬件角度估算内存上限也是必要步骤。每个后端进程的基础内存占用大约在 2 MB 到 5 MB,复杂查询还会分配额外的 work_mem。可以用下面的公式粗略计算:
# 假设每个连接基础内存按 5MB 计算,work_mem 按每次排序可能使用 4MB 计算 # 总连接数 = 可用内存 / (基础内存 + 平均 work_mem) # 例如 8GB 可用内存,保守评估: # 8000 / (5 + 4) ≈ 888 # 但实际还要扣除操作系统、共享缓冲区、其他进程占用,通常取更小的值
这个公式只能作为粗略参考,因为 work_mem 是每个排序操作而不是每个连接分配的,实际内存波动很大。更稳妥的方式是在测试环境用 pgbench 逐渐调高连接数,观察 TPS 和内存使用情况。往往你会发现,当连接数超过某个阈值后,TPS 反而下降,因为上下文切换和锁竞争开始占据主导地位。
常见误区与连接池的正确使用方式
第一个常见误区是把 max_connections 和应用连接池的最大连接数画等号。比如 Java 应用使用 HikariCP,配置 maximumPoolSize=200,就认为数据库也需要支持 200 个连接。实际上如果应用实例有 10 个,每个实例 200 个连接,数据库就需要承受 2000 个连接,这往往是灾难性的。正确做法是让应用连接池的总连接数远远大于数据库侧的连接数,中间通过 PgBouncer 或 Pgpool-II 做连接复用。数据库侧只需要承载实际同时执行的 SQL 数量,而不是应用持有的连接总数。
第二个误区是忽略了 superuser_reserved_connections 参数。这个参数默认为 3,表示为超级用户保留的连接数。当普通用户的连接数达到 max_connections - superuser_reserved_connections 时,新连接会报错:remaining connection slots are reserved for non-replication superuser connections。很多应用日志里出现这个错误时,DBA 的第一反应是继续调大 max_connections,但实际上应该先检查连接泄漏或连接池配置问题。如果应用用完连接不释放,再大的上限也会被耗尽。
第三个误区是在没有连接池的情况下盲目调低连接数。有些优化建议会告诉你 max_connections 越小越好,但如果应用直接连接数据库且并发较高,连接数太小会导致大量请求排队甚至超时。此时应该先引入连接池,再逐步降低数据库连接数,否则应用会频繁出现无法获取连接的异常。
下面是一个使用 pgbench 测试不同连接数下性能的示例:
# 初始化测试表 pgbench -i -s 50 mydb # 测试 50 个连接 pgbench -c 50 -j 10 -T 60 mydb # 测试 200 个连接 pgbench -c 200 -j 20 -T 60 mydb # 对比两次的 TPS 和响应时间,观察性能拐点
通过对比不同 -c 参数下的 TPS,可以找到数据库在当前硬件下的最优并发区间。通常建议 max_connections 设置在这个拐点附近,而不是无限放大。
监控连接使用情况并持续调整
设置完 max_connections 之后,不能一劳永逸。业务增长和架构变化都会影响连接需求,需要建立监控告警。最简单的监控指标是当前连接数占最大连接数的比例,当比例超过 80% 并持续一段时间时,就应该排查是正常业务增长还是连接泄漏。
可以通过下面的 SQL 查看当前连接数及每个数据库的连接分布:
SELECT datname,
count(*) AS connections,
count(*) FILTER (WHERE state = 'active') AS active
FROM pg_stat_activity
GROUP BY datname
ORDER BY connections DESC;
如果想查看哪些客户端地址占用了大量连接,可以用 client_addr 字段进行聚合。当发现某个应用服务器的连接数异常高时,通常意味着连接池没有生效或者存在连接泄漏。结合 pg_stat_activity 中的 backend_start 和 state_change 时间,可以识别出长期处于 idle in transaction 状态的连接,这种连接不仅占用槽位,还会阻塞 VACUUM 操作,应该尽快断开。
当需要调整连接数时,优先考虑通过 ALTER SYSTEM 修改:
ALTER SYSTEM SET max_connections = '250'; -- 修改后需要重启数据库
重启前务必做好连接池切换和业务停写准备,避免正在执行的事务被强制中断。对于关键业务,可以在从库或测试环境先验证新连接数下的表现,再应用到主库。最终目标不是让 max_connections 看起来很大,而是让数据库在稳定的内存和 CPU 范围内,支撑真实的并发需求。
综合来看,max_connections 的合理值没有固定答案,它依赖于业务并发模型、硬件资源配置以及是否使用连接池。一个可操作的过程是:先监控实际活跃连接数,再根据内存和 CPU 核数设定初始值,通过压测找到性能拐点,最后用连接池将数据库连接收敛到必要的最小集合。这样才能避免因连接数设置不当引发的内存耗尽、性能下降或连接拒绝问题。
PostgreSQL最大连接数max_connections数据库连接池修改时间:2026-08-25 14:15:25