On this page
  1. Why does opening a connection per request break?
  2. How does a connection pool work?
  3. What about connection pooling at the database edge?
  4. Where AI coding assistants get this wrong
  5. Checklist
  6. FAQ
    1. How many connections should my pool have?
    2. What is transaction-mode pooling in PgBouncer?
  7. Related topics
  8. Sources
concept

What Is a Connection Pool?

A connection pool reuses database connections instead of opening one per request. Learn why your app hits 'too many connections' and how pooling fixes it.

Quick answer

  • A connection pool keeps a small set of database connections open and reuses them across requests.
  • Opening a connection per request is slow and exhausts the database’s connection limit under load.
  • Pool size should match your database’s limits and workload, not the number of users.

Why does opening a connection per request break?

Creating a database connection is expensive: TCP handshake, TLS, authentication, and session setup. Under concurrent load, a server that opens a connection per request can blow past the database’s connection limit (Postgres defaults to 100) in seconds, and every new connection adds latency. Users start seeing ‘too many connections’ and connection refused errors even though nothing is actually down.

How does a connection pool work?

At startup the pool opens a fixed number of connections and lends them to requests, returning them when the request finishes. Requests wait briefly for a free connection instead of creating one. Most ORMs and drivers ship a pool (Prisma, SQLAlchemy, psycopg, node-postgres). Tune the size: too small causes queueing, too large exhausts the database — a common starting point is 5-20 per app instance, not hundreds.

from sqlalchemy import create_engine

engine = create_engine(
    "postgresql+psycopg://user:pass@db/app",
    pool_size=10,          # connections held open
    max_overflow=5,        # extra connections under spikes
    pool_timeout=5,        # seconds a request waits for a free connection
)

What about connection pooling at the database edge?

When multiple app instances each run pools, total connections multiply — 10 instances x 15 connections is 150, over many database limits. A proxy like PgBouncer sits between apps and the database in transaction mode, letting many app connections share a few real database connections. Serverless functions, which create connections from cold starts, almost always need this.

Where this bites vibecoders

The exact failure mode vibecoders hit: the demo works, a few dozen people visit, and suddenly ‘remaining connection slots are reserved’ errors appear. AI assistants often generate code that creates a new connection per request (or per query), and they rarely tune pool sizes. Knowing that pooling exists — and that the pool is per-instance — fixes the most common ‘works locally, dies under load’ story there is.

Where AI coding assistants get this wrong

  • Creating a new database connection inside each request handler.
  • Never closing connections, leaking them until the limit is hit.
  • Setting pool size to a huge number, transferring the exhaustion to the database.
  • Forgetting that serverless instances each open their own pool, multiplying connections.

Checklist

  • Use your framework’s connection pool instead of per-request connections.
  • Size the pool to the database limit divided across your instances.
  • Set a sensible pool timeout so requests fail fast instead of hanging.
  • For serverless, use a proxy like PgBouncer or the platform’s pooled connection string.

FAQ

How many connections should my pool have?

Enough to serve peak concurrency, far below the database’s limit. A starting point is 5-20 per instance; if you run many instances, use a proxy so the total stays within the database’s limit.

What is transaction-mode pooling in PgBouncer?

It assigns a real database connection to a client only for the duration of a transaction, so thousands of client connections share a few dozen database connections. That’s what makes pooling work for serverless and many-instance setups.

Sources

Share: