Skip to content

Free calculator · Engineering

Check PostgreSQL connections, pool size and memory fit

Enter peak reads and writes, query time, your server and how the application connects. The check shows connection headroom, queries in flight (Little's law), a starting pool size, whether the hot working set fits in memory, and how an app cache changes database reads.

How this is calculated

The check applies a few standard formulas to your peak figures: connection use against usable slots, Little's law for queries in flight, the (cores × 2) + spindles pool-size starting point, and a working-set-to-memory ratio. Each result gets a status from thresholds you can change.

Step by step

  1. Usable connections = max_connections − reserved slots. Client connections = app instances × pool size per instance.
  2. Server connections = client connections, or the recommended pool when a transaction pooler (PgBouncer transaction mode or RDS Proxy) sits in front. Connection use = server connections ÷ usable connections: good below 70%, watch from 70% to 90%, risk above.
  3. Queries in flight (Little's law) = (reads/s + writes/s) × average query time in seconds: good up to the number of cores, watch up to twice that, risk above.
  4. Recommended pool = the larger of (cores × 2) + effective spindle count and in-flight queries × (1 + headroom) rounded up, at least 1 and at most the usable connections.
  5. Memory fit = hot working set ÷ RAM: good up to 0.6, watch up to 1.0, risk above (a heuristic).
  6. Database reads after the app cache = reads/s × (1 − hit ratio). Cache memory = objects × average object size.
  7. Serverless clients with no pooler are always a risk. The overall status is the worst of the checks.

Default assumptions

Assumptions marked adjustable can be changed in the calculator; the others are fixed parts of the model.

Default assumptions and their sources
AssumptionDefaultSources
Peak read queries per second (example)adjustable4,500 per secondNone
Peak write queries per second (example)adjustable350 per secondNone
Average query time (example)adjustable5 msNone
Database CPU cores (example)adjustable8None
max_connectionsadjustable100 connections
Reserved connection slotsadjustable3 connections
App instances that connect (example)adjustable15None
Pool size per instance (example)adjustable30 connectionsNone
Database memory (example)adjustable32 GBNone
Hot working set (example)adjustable40 GBNone
App cache hit ratioadjustable80%None
Objects held in the app cache (example)adjustable500,000None
Average cached object size (example)adjustable2 KBNone
Effective spindle count in the pool-size formulaadjustable1
Pool headroom above in-flight queriesadjustable25%None
Connection use that starts the watch bandadjustable70%None
Connection use that starts the risk bandadjustable90%None
Working set ÷ RAM that starts the watch bandadjustable60%
Working set ÷ RAM that starts the risk bandadjustable100%None
Connections per core in the pool-size formula2

What this doesn’t model

  • It checks one server at peak using averages. Real traffic has bursts and slow outliers, so leave headroom beyond what it shows.
  • The pool-size formula is a starting point from the PostgreSQL wiki and HikariCP, not a tuned value; load-test the pool you choose.
  • The memory check is a heuristic based on the working set you estimate, not a measurement of cache hit rates in PostgreSQL.
  • The status thresholds are planning thresholds you can change, not published limits.
  • Individual slow queries, lock waits and long transactions, which raise the time each query holds a connection.
  • Disk IOPS and throughput; the memory check only says whether the hot data is likely to fit in RAM.
  • Read replicas and replication lag; enter one server's figures.
  • Autovacuum, table bloat and maintenance work, which use CPU and I/O alongside queries.
  • The cache's own per-key overhead and eviction policy; cache memory is the raw object data.

Sources

  1. PostgreSQL Global Development Group, Connections and Authentication (PostgreSQL 18 documentation). Accessed . max_connections is typically 100 by default; superuser_reserved_connections defaults to 3 and reserved_connections to 0.
  2. PostgreSQL Global Development Group, Resource Consumption (PostgreSQL 18 documentation). Accessed . On a dedicated server with 1GB or more of RAM, a reasonable starting shared_buffers is 25% of memory; PostgreSQL also relies on the operating system cache.
  3. PostgreSQL wiki, Number Of Database Connections (14 Mar 2014). Accessed . A starting point for active connections: ((core_count * 2) + effective_spindle_count); spindle count is zero if the active data set is fully cached.
  4. HikariCP (Brett Wooldridge), About Pool Sizing. Accessed . connections = ((core_count * 2) + effective_spindle_count); a 4-core server with one disk gets 9.
  5. PgBouncer, PgBouncer features. Accessed . Session pooling assigns a server connection for the whole time a client stays connected; transaction pooling only during a transaction.
  6. Amazon Web Services, Amazon RDS Proxy. Accessed . RDS Proxy pools and reuses database connections, queues or throttles connections it can't serve at once, and pins a session in some cases (for example statements over 16 KB).
  7. John D. C. Little, INFORMS, Little's Law as Viewed on Its 50th Anniversary (Operations Research 59(3), 536–549) (May 2011). Accessed . The average number of items in a queuing system equals the average arrival rate multiplied by the average time an item spends in the system: L = λW.

Last reviewed by the QuantmHill engineering team. Found an error?

Link to or cite this tool

Writing about this topic? Link to the calculator or cite it. Its method, defaults and sources are all on this page, so readers can check the numbers.

Embed this calculator

You can put this calculator on your own site for free. Paste the code below where it should appear. It loads the same calculator in a frame, with a link back to this page for the full method and sources.

The credit line links to this page with the anchor text “QuantmHill”. You may edit it, add rel="nofollow" or remove it — the calculator works the same either way. Add ?theme=light or ?theme=dark to the iframe address to fix its colour scheme; otherwise it follows the visitor's system setting.

Add this once per page, after the iframe, if you want the frame to grow and shrink with the calculator instead of using the fixed height above. It accepts messages from quantmhill.com only and resizes only the frame that sent them.

Frequently asked questions

Four things for one PostgreSQL server at peak: how much of max_connections your clients use, how many queries are in flight at once compared with CPU cores, a starting connection pool size, and whether your hot working set is likely to fit in memory. It also shows how many reads still reach the database behind an app cache, and how much memory the cached objects need.

It takes the larger of two figures: (cores × 2) + effective spindle count, the starting point the PostgreSQL wiki and HikariCP's 'About Pool Sizing' both give, and the queries in flight at peak plus a headroom you set (25% by default). The result is capped at the connection slots left after reserved ones.

PgBouncer's documentation describes transaction pooling as assigning a server connection to a client only during a transaction, so hundreds of client connections can share a small server pool. In session mode each connected client keeps its own server connection, so it doesn't help with connection counts. RDS Proxy also pools and reuses connections, though some statements pin a session to one connection.

Each concurrent function instance can open its own database connection, so a traffic spike can use up max_connections quickly. Without a pooler in front, the tool marks this as a risk whatever the other figures say.

Little's law says the average number of items in a system equals their arrival rate times the average time each spends there (John D. C. Little, Operations Research, 2011). For a database, queries per second × average query time in seconds gives the queries running at once. When that is well above the number of CPU cores, queries queue and response times rise.

No, it is a heuristic. It compares the hot working set you estimate with server memory. PostgreSQL's documentation suggests about 25% of RAM for shared_buffers on a dedicated server and relies on the operating system cache for the rest, so a working set well under RAM is likely to stay in memory. Check real cache hit rates in pg_stat_database.

Want an engineer to check your numbers?

Send us your inputs and the decision you're weighing. We'll reply within one business day with an honest read on whether we can help.