Database Connectivity Loss#
Symptom#
A service that depends on a database starts failing while the rest of the stack stays healthy:
Storage Service — reads and writes succeed, but user metadata operations, version history or optimistic-locking operations fail.
Permission Service — every authorization decision fails, so callers see permission denials across all services that consult it.
User Info Service — user and group lookups fail or return stale results.
Blast radius#
Depends on which database:
Database |
What fails |
|---|---|
Storage metadata (PostgreSQL / CosmosDB) |
User metadata and version-aware operations. Plain object read and write continue. |
Permission Service |
Authorization decisions. Because other services call it, this presents as a stack-wide outage even though only one component is down. |
User Info Service |
Identity lookups. Anything resolving a user or group by name degrades. |
The Permission Service case is the one to recognise quickly: a database failure in one component looks like a global permissions outage.
Triage#
1. Confirm it is the database, not the service.
kubectl -n <namespace> logs deployment/<service> --since=15m | grep -i -E 'connection|timeout|refused|pool|postgres|cosmos'
Connection-pool exhaustion, refused connections and authentication failures all name themselves here, and they mean different things — the next steps differ.
2. Is the database itself up?
For a CloudNativePG-managed cluster:
kubectl -n <pg-namespace> get cluster
kubectl -n <pg-namespace> get pods -l cnpg.io/cluster=<cluster-name>
kubectl -n <pg-namespace> describe cluster <cluster-name> | tail -30
A cluster stuck without a primary, or a pod that cannot attach its volume, explains the outage directly.
3. Is it reachable from the service?
kubectl -n <namespace> exec deployment/<service> -- \
sh -c 'nc -zv <db-host> 5432' 2>&1 | tail -2
Reachability failing while the database is healthy points at network policy, DNS, or a changed service name — see Loss of Connectivity: Backend and Egress.
4. Did the credential change?
An authentication failure that begins abruptly, with no deployment change, is almost always a rotated secret that the service has not picked up. See Secret Rotation and Credential Expiry.
kubectl -n <pg-namespace> get externalsecret
kubectl -n <pg-namespace> get secret <db-secret> -o jsonpath='{.metadata.creationTimestamp}'
5. Is it capacity rather than availability?
Connection-pool exhaustion under load looks like an outage but is a sizing problem. Check connection counts against the server’s limit before restarting anything:
kubectl -n <pg-namespace> exec <pg-primary-pod> -c postgres -- \
psql -U postgres -tAc "select count(*), (select setting from pg_settings where name='max_connections') from pg_stat_activity;"
Fix#
Database down — recover the database cluster first; the adapters reconnect on their own once it is reachable. Do not restart the adapters while the database is down; they will crash-loop and tell you less.
Credentials rotated — follow Secret Rotation and Credential Expiry. Restarting the consuming pod is usually required only if it caches the credential at startup.
Pool exhausted — raise the pool size or the server’s connection limit in your deployment values, and look for the caller that changed behaviour. A sudden pool exhaustion with unchanged configuration is a workload change, not a configuration fault.
Network path broken — see Loss of Connectivity: Backend and Egress.
Warning
Deleting and recreating a database cluster to “reset” it destroys its volume and its data. For the metadata and permissions databases that is a data-loss event, not a restart. Recover the existing cluster instead, and take a backup before any destructive step.
Verify#
The service’s own logs show successful connections and stop reporting pool or timeout errors.
The specific capability returns: user metadata reads succeed, authorization decisions resolve, or identity lookups answer.
Connection count sits well below the server limit under normal load.