Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Your app can run out of PostgreSQL connections under load even when each individual process has a modest pool: every replica, worker, and service can create its own pool, and those pools add up against the database’s finite connection limit. First calculate the deployment-wide maximum; then decide whether to reduce app-side concurrency, use PgBouncer to share server connections, or cautiously raise PostgreSQL’s limit.

Why connection errors appear as traffic or instances increase

PostgreSQL limits concurrent server connections with max_connections. PostgreSQL 18 documentation says its default is typically 100, but that is neither a universal setting nor a recommended target. The actual configured value, reserved connection slots, and any hosting-provider limits determine how many connections are available to ordinary clients. See the PostgreSQL 18 connection settings.

An application pool is usually configured per process, worker, or node—not once for the whole deployment. If each replica runs several worker processes, each with its own pool, the aggregate ceiling can grow rapidly as replicas or workers are added. Count every application and service that connects to the database, not just the web tier.

Calculate the deployment-wide connection ceiling

Use this planning formula for each service:

maximum app-side connections = replicas × worker/process count per replica × pool maximum per worker/process

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Add the results across services, then include background workers, scheduled jobs, migration processes, monitoring, and administrative clients. This is an upper-bound estimate: actual connections depend on the pool library and workload, but it exposes configurations that could exceed the database budget. Posit’s Connect deployment guidance illustrates how per-node pools multiply in a cluster; its product-specific defaults should not be assumed for other applications.

Compare that total with the database’s usable connection capacity, rather than comparing one worker’s pool setting with max_connections. Reserved slots affect access at the limit, and other services or provider constraints may consume or restrict capacity.

Use metrics to identify the actual bottleneck

Inspect the failure window, not just a quiet-period snapshot. Application pool wait times and checkout timeouts show whether requests are waiting for the app’s own pool. Database connection counts show whether sessions are nearing the server limit. If you use PgBouncer, its usage documentation describes counters for current client and server connections and their configured maxima. Many clients with fewer server connections suggests multiplexing and queueing; a client count at its configured maximum can instead point to the pooler’s client limit.

Also investigate what keeps connections occupied: slow queries, long transactions, idle-in-transaction sessions, or code that checks out a connection well before it needs one and returns it late. Reducing time spent holding a connection can improve availability without raising any limit.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choose a fix based on the constraint

Option When it fits Trade-off to check
Reduce per-process pool maxima or replica/worker count The deployment-wide configured ceiling exceeds the database connection budget, or excessive app-side concurrency is creating pressure. Requests may wait longer for an app-side connection if the pool is made too small; monitor pool waits and timeouts.
Add PgBouncer Many app clients need to share a smaller controlled set of PostgreSQL server connections. Pooling mode changes connection-state behavior, and PgBouncer adds an operational component to configure and monitor.
Raise PostgreSQL max_connections Measurements and resource checks show the server can support the additional concurrent sessions and other remedies are insufficient. PostgreSQL allocates some resources based directly on this setting; the setting can only be changed at server start. Provider limits may also apply.

More simultaneous database sessions do not necessarily produce more throughput. Once server resources are saturated, contention can increase latency and reduce throughput. The PostgreSQL community’s connection-count guidance explains why controlling active work and queueing can be preferable to continually adding sessions.

Understand PgBouncer’s pooling modes before switching

PgBouncer’s configuration reference defines three modes, which determine how long a PostgreSQL server connection remains assigned to a client:

  • Session pooling: the server connection returns to the pool when the client disconnects.
  • Transaction pooling: it returns when the transaction ends, allowing another client to use it between transactions.
  • Statement pooling: it returns after a query; transactions spanning multiple statements are disallowed.

Transaction pooling is often useful when many application clients need to share fewer server connections, but it is not behaviorally transparent for every application. Check whether your code depends on session variables, temporary tables, advisory locks, session-level prepared statements, or other state persisting across transactions. Verify the deployed PgBouncer and driver versions against the application’s actual behavior.

Prepared-statement handling is version-sensitive. PgBouncer’s FAQ says that, since version 1.21.0, transaction pooling can track prepared statements and prepare them on the linked server connection when max_prepared_statements is set to a non-zero value. The FAQ also notes compatibility constraints for PHP/PDO versions and a JDBC configuration consideration; check its current guidance rather than assuming every driver configuration is compatible.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Size and operate PgBouncer deliberately

The PgBouncer configuration reference documents defaults of 20 server connections for default_pool_size per user/database pair and 100 client connections for max_client_conn. These are software defaults, not a sizing formula or recommended values for your deployment. The number of user/database pools, PostgreSQL’s capacity, and your topology all affect the total server-side connection demand.

The same reference warns that increasing max_client_conn may require raising operating-system file-descriptor limits. Set client and server pool limits with the host’s resource limits and database budget in view, then monitor client counts, server counts, and application wait behavior as traffic changes.

A practical order of operations

  1. Inventory connection creators: list replicas, processes or workers per replica, pool maxima, background jobs, migrations, monitoring, and other database clients.
  2. Calculate the aggregate upper bound: apply the per-service formula and compare the total with actual usable server capacity, including reserved slots and provider restrictions.
  3. Measure during errors: check application pool waits and timeouts, database connection counts, and—if present—PgBouncer’s current client/server counts and configured maxima.
  4. Reduce avoidable demand: correct oversized per-process pools or excess concurrency, and investigate slow queries, long transactions, and connections held longer than necessary.
  5. Evaluate multiplexing: if many clients need access to limited server capacity, test an appropriate PgBouncer mode against session-state and driver requirements.
  6. Change the server limit only with evidence: verify resource headroom, provider constraints, restart implications, and workload behavior before raising max_connections.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.