April 27, 2020·4 min read·engineeringpostgresqlpoolingoperations

PgBouncer 1.13 makes connection behaviour more explicit

PgBouncer 1.13 adds a Linux TCP timeout, changes permitted TLS versions and reports readiness to systemd. Each change controls a different part of connection management.

A running connection pooler has several different responsibilities. It must manage database connections, apply transport settings and report its own process state to the service manager. PgBouncer 1.13.0 changes the controls around those responsibilities. The April 27 announcement names a new TCP timeout, revised TLS defaults and systemd integration as the main additions to this PostgreSQL connection pooler.

The scope is useful because these settings answer different operational questions. A transport timeout describes a stalled connection, while a protocol allowlist constrains a TLS negotiation. Readiness notification describes a point reached by the pooler process. Treating any one of them as a complete declaration of database health would give it a meaning broader than the implementation supports.

I prefer PostgreSQL for relational systems, so the behaviour of the software between an application and PostgreSQL matters to me. A pooler adds configuration whose meaning needs to remain legible during maintenance. This release provides explicit controls, but understanding the layer each control affects is more useful than enabling every new option.

TCP acknowledgement has its own timeout

The versioned configuration reference defines tcp_user_timeout in milliseconds. It sets the maximum time transmitted data may remain unacknowledged before TCP forcibly closes the connection. The setting is supported on Linux, and its default of zero leaves the operating system's default in effect.

That describes a transport condition. It does not establish an execution deadline for a SQL statement. A connection that acknowledges network traffic can still be occupied by database work. Conversely, transmitted data that receives no acknowledgement can exhaust this timeout without the database having evaluated the intended statement. Those cases need different explanations when an application reports a connection error.

An illustrative fragment sets a thirty-second acknowledgement limit:

[pgbouncer]
tcp_user_timeout = 30000

The number expresses a local policy choice, not a recommendation from the release. Its unit matters because confusing milliseconds with seconds changes the limit substantially. The useful property is that the setting names the stalled TCP condition directly, instead of requiring an operator to infer it from a query timeout.

TLS protocol selection changes on both sides

The 1.13.0 changelog changes both client_tls_protocols and server_tls_protocols to the secure default. In this release that permits TLS 1.2 and TLS 1.3. Earlier protocol versions remain supported by configuration, but are no longer enabled by the default allowlist.

The two names distinguish client-facing connections from connections to PostgreSQL. Updating the default for both is useful because a pooler participates in separate negotiations. A successful negotiation on one connection does not describe the protocol used on the other. An inventory of old clients and servers therefore has to consider both directions.

The change also needs to be read narrowly. A permitted protocol list describes which TLS versions can be negotiated. It does not say that every connection now uses TLS. The configuration reference separately documents server_tls_sslmode, whose default disables TLS to PostgreSQL. Protocol selection and the decision to require encryption are independent settings.

I favour defaults that reduce the number of obsolete protocols an ordinary deployment accepts. Keeping an explicit compatibility option is still useful for administrators who can identify a remaining dependency. That decision should refer to the specific endpoint requiring compatibility, since the two sides of a pooler need not have identical requirements.

Readiness becomes a process notification

The new systemd support permits Type=notify service units. The example service file shipped with 1.13.0 uses that type and starts PgBouncer with a configuration file. It also specifies a reload command that sends SIGHUP and a stop signal of SIGINT.

The example includes a deployment detail that is easy to overlook. Its comments discuss permissions for the Unix socket directory. Running the pooler under a particular account has to agree with the permissions on that directory and with the PostgreSQL packaging around it. A service unit cannot choose that policy independently of the installation's filesystem ownership.

The main program source shows where notifications occur. Startup sends READY=1 after initialization and pooler setup, immediately before entering the main event loop. Its SIGHUP handler sends RELOADING=1, reloads configuration, then sends READY=1. The SIGINT handler reports STOPPING=1 as shutdown begins.

Those locations give the notification a concrete interpretation. It records progress through PgBouncer's lifecycle, including startup, configuration reload and the beginning of shutdown. Nothing at the startup notification establishes that a particular application transaction has succeeded or that its required database objects are present. Service management gains a more precise process state, while a check that exercises an application's database access continues to answer a separate question about that access path.