I fixed a database slowdown by adding an index, then briefly credited the Go connection pool. This was generous of me and inaccurate.

*sql.DB manages underlying driver connections and permits concurrent use. Left alone, it can open more connections as concurrent work arrives. That is convenient until the database reaches its own useful concurrency limit.

The development tree for the upcoming Go 1.2 release has added SetMaxOpenConns, which turns the pool into a concurrency bound. Code staying on Go 1.1 still needs to bound database work before it reaches *sql.DB; when 1.2 lands, the limit can live on the handle itself:

db.SetMaxOpenConns(20)

Once 20 connections are in use, another database operation waits for one. That can protect a server from a burst, but it moves queueing into the application. A lower database CPU graph paired with rising request latency may simply mean callers are waiting at the pool.

The limit also makes connection lifetime matter more. An open result set or transaction occupies one slot. Calling back through db while holding a transaction can deadlock when every slot is similarly occupied: each holder waits for a new connection, and none can finish to release one. Code under a transaction should use tx and keep that scope short.

SetMaxIdleConns answers a different question. Idle connections reduce setup cost but consume server resources; the open limit bounds active plus idle connections. Setting both to the same number can keep a warm pool, while a smaller idle limit lets unused connections go. The right values depend on server capacity and traffic, not the number of goroutines I can create.

I watch query latency at the database, total application latency around calls, server connection counts, and request concurrency. In this Go version there is no convenient pool statistics API, so the gap between server query time and time around the call is especially useful evidence of waiting.

A connection limit is backpressure, not acceleration. I set it from measurements of the real database, then test saturation rather than only an idle local server. It still cannot compensate for a missing index; that is asking the pipes to improve the water.