Connections Are Expensive
Opening a database connection costs a network round trip, authentication, and server side memory. A connection per request would exhaust the database quickly. A connection pool keeps a bounded set of open connections and lends them to requests, returning each to the pool when done.
Why Bound the Pool
Every database has a hard limit on concurrent connections. Each connection consumes memory and a backend process or thread, so a few thousand connections can crush a server even if most sit idle. A bounded pool protects the database by capping concurrency. When all connections are busy, new requests wait in a queue rather than overwhelming the server.
The Fan In Problem
At scale this gets tricky. Imagine one hundred application servers, each with a pool of one hundred connections. That is ten thousand possible connections into a database that can only handle a few thousand. The pools are sized in isolation but sum at the database.
The fix is a shared external pooler that sits between apps and the database, multiplexing many client connections onto a small number of real backend connections. This decouples app side concurrency from database side connection count.
Key idea
A bounded connection pool reuses costly connections, but independent pools sum at the database, so a shared external pooler multiplexes many clients onto few backends.