Skip to main content
Metrics type: Supporting MetricsCategory: Errors

At a glance

The count of failed connection attempts to your PostgreSQL instance over the trailing 24 hours. For a platform team, this is “how often did something try to connect and get turned away?” A handful of errors is background noise (a restarting pod, a stale credential rotating out). A wall of them means clients cannot reach the database: the pool is exhausted, max_connections is too low, pg_hba.conf is rejecting hosts, or the instance is refusing logins during recovery. Sustained connection errors translate directly into application 5xx responses, so this is an early warning that surfaces before your app-tier dashboards light up.

Calculation

The card counts every connection attempt that failed to produce a usable backend in the trailing 24 hours. The primary signal is the PostgreSQL server log: Vortex IQ matches log lines emitted at FATAL severity during the connection-establishment phase, classifying each into one of the five categories listed above. Where log_connections and log_disconnections are enabled, the engine cross-checks the count of connection-authorised lines against connection-received lines to catch failures that never reached the log filter. On a self-managed instance the dominant contributors are visible directly in the log and, for slot exhaustion specifically, can be inferred from pg_stat_activity hitting max_connections. On managed services (Amazon RDS / Aurora, Cloud SQL, Azure Database for PostgreSQL) the raw log access is supplemented by the provider’s own failed-connection metric (for example the RDS DatabaseConnections ceiling against max_connections, or Cloud SQL’s connection-error counter) so the figure stays accurate even when log retention is short. The result is a single integer: the total number of rejected connection attempts in the window. The alert fires when that integer exceeds 100.

Worked example

A SaaS platform team runs a primary PostgreSQL 15 instance behind PgBouncer, serving an order-management API. max_connections is set to 200; PgBouncer holds a server pool of 180. Snapshot taken on 14 Apr 26 at 09:50 BST, the morning after a release. The Nerve Centre headline reads 232 connection errors (24h) and the card is amber because the threshold of 100 has been crossed. The shape matters more than the total: the first seven hours are flat background noise (a credential rotation generating a few auth failures, entirely benign). The signal is the cliff at 08:30, where pool exhaustion errors jump from single digits to 142 in thirty minutes. What happened: the 08:00 release introduced a code path that opened a new connection per request instead of reusing the pooled connection. As morning traffic ramped, the application drained PgBouncer’s server pool, then PgBouncer itself began failing to hand out client slots, and PostgreSQL started returning FATAL: sorry, too many clients already. Every one of those 142 + 71 errors is a request the API could not serve: a 503 to a customer. The platform team’s read, in order:
  1. Ignore the overnight auth errors. Four to ten per hour from a rotating credential is expected and is not what tripped the alert. Filtering by category in the drill-down confirms they are flat.
  2. Confirm the cause is the pool, not the database. Cross-reference Connections In Use and Connection Pool Saturation %. If saturation is pinned at 100% during the 08:30 cliff, the database is healthy but the pool is starved, which points at the application, not at max_connections.
  3. Decide the mitigation. Short term: roll back the 08:00 release or raise the PgBouncer pool size. Long term: fix the connection-per-request leak. Raising max_connections is the wrong lever here because the problem is client behaviour, and more backends means more memory pressure (each backend costs roughly work_mem plus overhead).
Three things worth remembering:
  1. Read the shape, not just the total. 232 errors spread evenly over 24 hours (background credential churn) is a different world from 232 concentrated in a 90-minute cliff. The alert fires on the total, but the drill-down spark line tells you whether you have a chronic config problem or an acute incident.
  2. Connection errors are an upstream leading indicator. They show up here before they show up as 5xx on your app dashboards, because the failure happens at connect time. Treat a rising count as a head start.
  3. The fix is rarely “more connections”. Pool exhaustion almost always means a client misbehaving (leaking connections, not pooling) rather than a database that is genuinely too small. Diagnose with the saturation and in-use cards before changing max_connections.

Sibling cards to reference together

Reconciling against the source

Where to look in PostgreSQL’s own tooling:
Server log is the authoritative source. With log_connections = on, every accepted connection is logged; failed attempts are logged at FATAL regardless. Grep the log for too many clients, password authentication failed, and no pg_hba.conf entry to reproduce the per-category counts. pg_stat_activity shows the live backend count: SELECT count(*) FROM pg_stat_activity; against SHOW max_connections; tells you how close you are to slot exhaustion right now. pg_stat_database exposes xact_commit and xact_rollback for committed work, but note that connection rejections never create a backend, so they do not appear here, the server log is the only complete record. Managed-service console: on Amazon RDS / Aurora, the CloudWatch DatabaseConnections metric against the max_connections parameter, plus the Enhanced Monitoring and Performance Insights connection panes. On Cloud SQL, the database/postgresql/num_backends metric and the connection-error logs in Cloud Logging. On Azure Database for PostgreSQL, the connections_failed and active_connections metrics in Azure Monitor.
Why our number may legitimately differ from a raw log grep: Cross-connector reconciliation:

Known limitations / FAQs

My count is non-zero every day even when nothing is wrong. Is that normal? Yes. A small, flat background level of connection errors is expected in almost every environment: pods restart, credentials rotate, health-check probes occasionally race a restart, and the odd misconfigured client tries the wrong password. The threshold sits at 100 over 24 hours precisely so this background noise does not page anyone. Watch the shape: a flat low line is healthy; a sudden cliff is the signal. I use PgBouncer. Does this card see errors that PgBouncer rejects before they reach PostgreSQL? Only if the connector has access to PgBouncer’s own log or its SHOW STATS / SHOW POOLS output. When PgBouncer turns a client away at its own pool boundary, the PostgreSQL server log never records it. Where Vortex IQ can read the pooler, those rejections are folded in; where it cannot, pooler-side rejections are undercounted at the database layer. Pair with PgBouncer Pool Saturation vs Traffic Burst for the pooler-side view. The card spiked but pg_stat_activity shows plenty of free slots. What does that mean? Slot headroom rules out too many clients, so the errors are a different category: almost certainly authentication failures or pg_hba.conf rejections. Filter the drill-down by category. A burst of password authentication failed usually means a credential rotated and a client did not pick up the new secret; a burst of no pg_hba.conf entry means a new host or subnet is trying to connect and is not allow-listed. Should I raise max_connections to stop the errors? Usually no. If the cause is pool exhaustion, the real problem is a client that is not pooling or is leaking connections, and raising max_connections just defers the wall while increasing memory pressure (each backend consumes memory). Fix the client first. Raise max_connections only when you have genuinely outgrown capacity and have confirmed the pooler is sized correctly. Connection errors are zero but my app is returning database errors. Why? Because those are query errors, not connection errors. The app connected fine, then a query failed (a statement timeout, a constraint violation, a lock wait, a deadlock). This card only counts failures at connect time. Look at Query Error Rate % and Deadlocks (last 5m) for the post-connection failure picture. Does a restart of the database inflate this count? Briefly, yes. During startup and crash recovery PostgreSQL rejects connections with the database system is starting up / is in recovery mode. Clients retrying during that window each register an error. A short burst immediately after a planned restart is expected and self-clears; correlate the spike timestamp with Instance Uptime to confirm it lines up with a restart rather than an ongoing fault. Can I change the alert threshold of 100? Yes. The threshold is configurable per profile in the Alert Rules tab. A high-churn microservices environment with aggressive credential rotation may need a higher floor; a small, stable single-app database may want it lower so any meaningful uptick is caught. Tune it to your own baseline rather than the generic default.

Tracked live in Vortex IQ Nerve Centre

Connection Errors (24h) is one of hundreds of KPI pulses Vortex IQ tracks across PostgreSQL and 70+ other ecommerce connectors. Nerve Centre runs the detection layer; Vortex Mind investigates the cause when something moves; Ask Viq lets you interrogate any number in plain English. Start for free or book a demo to see this metric running on your own data.