A relational database server enforces a maximum number of concurrent client connections. Explain what each connection actually costs the server, what happens when the cap is reached, and how you would reason about setting it.
answer
- Fixed MBs per session + per-operation work memory
- Peak ~ conns x (fixed + ops x work_mem)
- At cap: new logins refused, admin slots reserved
- Retry storms amplify saturation
- Cap is a guardrail; derive from summed pool maxima
basics
~20 sEach connection costs a server-side process or thread, several megabytes of private memory, plus per-query workspace that multiplies under load. At the cap, new connections are rejected outright. Set it just above what your pools can actually use, since real throughput is bounded by cores and disk, not by connection count.
solid answer
~60 s**Cost per connection**: a backend process or thread; fixed private memory (catalog and plan caches, parse workspace) typically in the low megabytes; plus *per-operation* workspace - sort and hash buffers - that can be allocated multiple times per query. So worst-case memory is roughly connections x (fixed + concurrent operations x work memory), which is why a high cap is a memory time bomb rather than a harmless setting. **At the cap**: new connection attempts are refused with a "too many connections" error, usually with a few slots reserved for administrative logins so an operator can still get in and investigate. Existing sessions keep working. Applications typically then retry, which amplifies the storm. **Setting it**: work backwards. Real concurrency is bounded by CPU cores and storage parallelism - a few dozen active statements on typical hardware. Size application pools to that, sum pool maxima across every instance and every side channel (migrations, cron jobs, admin tools, replicas' feeds), add headroom for admin sessions, and set the cap slightly above that sum. Then enforce it with pooling rather than hoping clients behave.
code
text · 10 linesuseful concurrency (16 cores, mixed OLTP) ~ 32 active statements
app instances = 12
pool max per instance = 8 -> 96
batch/cron workers (4 x 4) = 16
migration + admin tooling = 8
monitoring + backup agents = 6
---------------------------------------------------------
summed client demand = 126
admin reserve + burst headroom = 24
cap = 150 (not 1000)go deeper
Know that connections are capped, that each one costs memory, and that exceeding the cap rejects new logins while existing sessions continue.
Show the memory arithmetic including per-operation work memory, and explain why more connections do not mean more throughput.
Diagnose the demand side - idle versus idle-in-transaction, pool maxima, connection churn - and derive the cap from summed bounded demand plus admin headroom.
Own the fleet-wide connection budget: allocate limits across services and tools, define retry and backoff policy to prevent storms, and treat 'raise the cap' as a defect in the plan.
## Where per-connection memory goes Every session gets its own memory, and it comes in two very different flavours. **Fixed overhead.** The backend's stack, its private catalog cache (metadata for the tables it touches), its plan and prepared-statement cache, and parser/executor scratch. This is on the order of a few megabytes per session and it exists even when the session is idle. A thousand idle sessions is not zero - it is gigabytes plus a thousand scheduler entries. **Query workspace.** Sort buffers, hash tables for joins and aggregation, and bitmap structures. Crucially this is allocated *per operation*, not per connection: one query with several sorts and hash joins can allocate the per-operation budget several times over. A configuration that looks safe at one active connection becomes an out-of-memory event at fifty. The worst-case arithmetic that matters in an interview: > peak memory ~ shared buffers + connections x (fixed per-session + concurrent memory-hungry operations x per-operation work memory) Most incidents where a database is killed by the OS out-of-memory reaper trace back to someone raising the connection cap or the work-memory setting without doing this multiplication. ## The cost that is not memory More sessions also mean more scheduler pressure, more cache-line contention on shared structures such as the buffer pool and lock manager, and, for process-per-connection engines, more page tables and context switches. Past the hardware's real concurrency limit, adding sessions makes total throughput *fall*, not plateau - the classic congestion curve. Two hundred active sessions on sixteen cores do not run faster than thirty; they run slower and with far worse latency variance. ## What happens at the cap The listener refuses new connections with an explicit "too many connections" style error. Established sessions are unaffected. Engines normally reserve a handful of slots for superuser or administrative logins precisely so an operator can still connect and see what is happening - a detail worth mentioning, because the alternative is a database you cannot diagnose. The dangerous dynamic is what happens next. Application instances see connection failures, treat them as transient, and retry immediately. Retries arrive faster than sessions are released, health checks start failing, orchestrators restart instances, and each restarted instance opens a fresh pool. That feedback loop turns a brief saturation into an outage, and it is why retry with backoff and jitter, plus a bounded pool, matter as much as the cap itself. ## Diagnosing connection pressure Look at the server's activity view and classify sessions rather than counting them: active, idle, and - the important one - **idle in transaction**. A pile of idle sessions is usually oversized pools; a pile of idle-in-transaction sessions is an application bug (a transaction opened and then left waiting on application logic or a remote call), and it is far more harmful because those sessions hold locks and block cleanup of old row versions. Also check whether connections are churning: high connect rate with short session lifetimes means something is not pooling at all. ## How to choose the number Do not start from the cap; start from useful concurrency. 1. Estimate real capacity - roughly the CPU cores available for query work plus some allowance for I/O-bound waits. This is tens, not thousands. 2. Size each application pool near that number divided across instances, and confirm it with latency under load rather than intuition. 3. Sum every consumer: application instances x pool maximum, plus background jobs, migrations, monitoring agents, replication and backup tools, BI clients, and human operators. 4. Add a margin for administrative sessions and a small burst allowance. 5. Set the cap a little above that sum - high enough that legitimate load is never refused, low enough that a runaway client hits a wall before memory does. The cap is a **guardrail, not a capacity plan**. If the answer to saturation is "raise the cap," the next event is an out-of-memory kill or a throughput collapse. The right answer is almost always to reduce demand for sessions - bound and share them - and to fix whatever holds them open. ## Interview framing The strong answer contains three moves: connections cost memory that multiplies per operation; useful concurrency is bounded by hardware so more sessions can reduce throughput; and the cap should be derived from the summed, bounded demand of every client rather than tuned upward in response to errors.
- Your service starts failing with "too many connections". Why is raising the cap usually the wrong first move?The cap is protecting the server from memory exhaustion and scheduler thrashing; raising it converts a clean, retriable rejection into an out-of-memory kill or a throughput collapse that affects every session. The real question is where the sessions are going - oversized or leaking pools, sessions stuck idle in transaction, or a client with no pooling at all. Fix the demand side first, and only then re-derive the cap from summed pool maxima.
- Why are sessions sitting idle in a transaction more damaging than sessions that are merely idle?An idle session consumes memory and a slot but holds nothing. An idle-in-transaction session still holds its locks and keeps an old snapshot alive, so it blocks conflicting writers and prevents the engine from cleaning up dead row versions, which bloats tables and degrades scans server-wide. They are usually caused by opening a transaction and then doing slow application work - a network call, user interaction - inside it, and a server-side idle-in-transaction timeout is the standard guardrail.
- Why can total throughput decrease when the number of active connections rises?Useful concurrency is bounded by CPU cores and storage parallelism. Beyond that point, extra sessions add context switching, cache pressure, and contention on shared structures such as the buffer pool and lock manager, so each unit of work takes longer while none complete sooner. The result is the classic congestion curve: throughput peaks, then falls, while latency variance grows sharply.
The connection cap is a venue's fire-code limit: it does not make the venue bigger, it stops the night ending badly. Raising it because a queue formed outside is how the floor collapses.
saying these in an interview costs you the question
- Treating the connection cap as a throughput setting to raise under load
- Ignoring that sort/hash work memory is allocated per operation, not per connection
- Assuming idle connections are free
- Believing existing sessions are terminated when the cap is reached
- Sizing the cap without summing every client, including jobs, tools, and agents