Connection routing
Login format
postgresql://USER.DEPLOYMENT[.pool]@PROXY_HOST:PORT/DATABASE
| Login | User sent to backend | Deployment | Pooled |
|---|---|---|---|
| alice.db1 | alice | db1 | no |
| alice.db1.pool | alice | db1 | yes |
| a.b.db1.pool | a.b | db1 | yes |
| alice | alice | none | no (no route matches, connection fails) |
| alice.pool | alice.pool | none | no (fails) |
The last dot separated part is the deployment, unless it is the word pool, in which case the part before it is the deployment. User names may contain dots.
Routing by TLS server name (SNI)
When the login has no deployment part and the client connected with TLS, the proxy uses the TLS server name instead:
| Client connects to host | Login | Deployment | Pooled |
|---|---|---|---|
| db1.example.com | alice | db1 | no |
| db1.pool.example.com | alice | db1 | yes |
The login always wins when it contains a deployment. This works after the normal SSLRequest upgrade and also for PostgreSQL 17 direct TLS (sslnegotiation=direct, ALPN postgresql), which the proxy detects by the first byte of the connection. Direct TLS needs TLS enabled on the proxy. A wildcard DNS record such as *.example.com pointing at the proxy is enough.
Database name
If the client sends no database, or the database equals the full login, the proxy sends postgres. Any other database name is forwarded as is.
Direct and pooled endpoints
One deployment can expose two backends: a direct one (for migrations, long transactions, LISTEN) and a pooled one (for application traffic). The client chooses by adding .pool to the login.
Errors a client can see
| Situation | Message | Code |
|---|---|---|
| No route for the login | no backend for this user; expected user.deployment[.pool] | 08001 |
| Backend cannot be reached | backend unavailable | 08001 |
| Connection limit reached | connection closed without a message | none |
| Startup too slow or malformed | connection closed without a message | none |
Details are in the proxy log, not in the client message.
Limitations
- Query cancellation from psql or drivers (CancelRequest) is not routed, because it carries only a process id and key. Cancel by connecting to the backend directly or with pg_cancel_backend.
- Protocol 3.0 and 3.2 are accepted.
- Every other startup parameter (options, application_name, client_encoding, …) is forwarded unchanged, which PostgreSQL-compatible databases rely on.