Connection Pooling Go
Fast recall
Quick revision
Core answer
Whether you understand Connection Pooling Go beyond memorized syntax.
Giving a definition without explaining a practical trade-off.
Connect the concept to a small production example and state its complexity or failure mode.
Interview-ready guide
Interview answer
The pool semantics:
db, _ := sql.Open("postgres", dsn) // returns a POOL — no connection yet
// Configure (do this once, right after Open):
db.SetMaxOpenConns(25) // never more than 25 concurrent connections
db.SetMaxIdleConns(5) // keep 5 warm (ready to hand out)
db.SetConnMaxLifetime(30 * time.Minute) // recycle to survive DB failovers
db.SetConnMaxIdleTime(5 * time.Minute) // drop idle unusedExecuted: our test database set pool limits successfully (max 25 open, 5 idle — verified).
The lifecycle of a query through the pool:
- 1Query/Exec requests a connection
- 2If an idle one is available → borrow it (fast — no handshake)
- 3If not and pool < MaxOpenConns → create a new connection
- 4If pool is at max → WAIT (the pool queue — queries block here under load)
- 5Query runs; the connection returns to idle (or closes if pool shrinks)
The production tuning: MaxOpenConns should be BELOW the DB's max (PostgreSQL defaults to 100 — a 5-instance deployment × 25 connections each = 125 > 100 = connection storms). SetConnMaxLifetime is the failover armor — connections die and get recreated without app errors.
The common bug: sql.Open per-request (each Open creates a NEW pool — connection storm, resource exhaustion). The db handle is long-lived, one per process, shared safely (it's built for concurrency).
Connection Pooling Go
Direct Answer
db.Open returns a pool, not a connection. Each Query borrows from the pool and returns it. Configure: SetMaxOpenConns, SetMaxIdleConns, SetConnMaxLifetime, SetConnMaxIdleTime. The DB handle is one-per-app.
Deep Dive & Architecture
The waiting behavior: when the pool is exhausted, Query BLOCKS until a connection frees — no error, just latency. The queue has no timeout by default (the context you pass carries the deadline — QueryContext with a 5s timeout bounds the wait). The observability: db.Stats() gives the live numbers (OpenConnections, InUse, Idle, WaitCount) — the pool dashboard for debugging exhaustion.
The driver-level pooling reality: each driver (pq, pgx) may have its own pool under the stdlib's — pgx's native pool is the high-performance alternative to the database/sql pool. The stdlib pool is the universal layer (any driver, any DB); the native pools are the optimized path.
The MaxIdleConns tuning trade: too few idles = cold connections on every burst (handshake latency); too many = the DB holds sockets for nothing. The default (2) is conservative — the tuning knob for bursty workloads (5-10).
Common Mistakes & Pitfalls
Giving a definition without explaining a practical trade-off.
Check your understanding
Answer these without looking back at the article.
- When would you use Connection Pooling Go in a real project?
- How would you compare Connection Pooling Go with an alternative?
- What is a common mistake when using Connection Pooling Go?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.