Skip to content

CONCEPT Cited by 1 source

Connection pool exhaustion

Definition

A connection pool is a fixed-size set of pre-established database connections shared across application workers. An application worker takes a connection from the pool for the duration of a query (or transaction), then returns it.

Connection pool exhaustion is the state where every connection in the pool is in use; new requesters either:

  • Wait for a connection to be returned (bounded-queue behaviour).
  • Get rejected immediately (fail-fast behaviour).
  • Create a new connection outside the pool (uncommon; defeats the pool's purpose).

Why it's a high-quality throttling signal

Among the metrics Shlomi Noach walks through in Part 1 of Anatomy of a Throttler (sources/2026-04-21-planetscale-anatomy-of-a-throttler-part-1), pool exhaustion is the one signal with a natural threshold:

"Who decides the size of the pool in the first place? If someone picked a number such as 50 or 100, isn't that number just artificial? It may well be, but pool size was likely chosen for some good reason(s). It is perhaps derived from some database configuration, which is itself derived from some hardware limitation. And while the choice of metric could possibly change arbitrarily, it is still sensible, as far as throttling goes, to push back when the pool is exhausted. The throttler thereby relies on the greater system configuration and does not introduce any new artificial thresholds."

In other words: the operator already chose a pool size based on:

  • max_connections in the database
  • Memory per backend (InnoDB / PostgreSQL backend overhead)
  • Expected concurrency profile
  • Connection-establishment cost / TLS handshake cost

A throttler that pushes back when the pool is 100% used inherits the existing system configuration as its threshold. It does not need to ask the operator to pick a new number.

Contrast with intermediate levels of utilisation

Pool exhaustion (100%) is a strong signal. Pool utilisation (60% vs 80%) is a much weaker one:

"An exhausted pool is a strong indication of excessive load, while the difference between a 60% and an 80% used pool is not as clear an indication."

This is why pool exhaustion is typically a binary throttling signal — "reject when full" — rather than a continuous one. Continuous levels conflate transient burstiness with sustained load in ways that are hard to separate without knowing workload shape.

Limits of the signal

  • Pool connections span transactions, not queries. A connection can be held across multiple queries in a transaction, across multiple transactions, and across application logic between them. Pool exhaustion therefore reports on held connections, not on actively executing ones — a subtle distinction from concepts/threads-running-mysql.
  • Per-pool, not per-database. Modern applications may have many pools (per-service, per-region, per-tenant); pool exhaustion in one does not necessarily indicate database-level distress.
  • Pooler-level pools (PgBouncer, ProxySQL, VTGate) introduce a second tier of exhaustion — the database can be unexhausted while the pooler is full, and vice versa.

Relationship to queueing theory

Pool exhaustion is the queue-full state of a bounded queue: the pool has capacity N, arrivals exceed the service rate so all N slots are occupied, and new arrivals are rejected or stall. See concepts/queueing-theory and concepts/backpressure for the broader framing.

Seen in

  • sources/2026-04-21-planetscale-anatomy-of-a-throttler-part-1 — canonical framing of pool exhaustion as the one throttling-signal metric with a natural, system-configuration- derived threshold. Noach lands on it as the positive counter- example to threads_running and load average, both of which lack a stable threshold.
Last updated · 319 distilled / 1,201 read