# 53300 — too_many_connections

> PostgreSQL reports SQLSTATE 53300 when a connection cannot be admitted because a connection limit is exhausted. Identify the role, database, or server limit and verify a fresh connection after capacity is restored.
---

## At a glance {#at-a-glance}

`53300` is PostgreSQL's `too_many_connections` condition in Class 53, `insufficient_resources`. It is emitted when a new backend cannot be admitted because a connection capacity limit has been reached. The representative case uses a role connection limit of one and opens a second session for that role.

This is a connection-startup failure. No SQL transaction is opened for the rejected session. In the final runs, psycopg reported the startup exception text but exposed `sqlstate=None`; the PostgreSQL collector recorded the server's actual `FATAL` SQLSTATE `53300`. Keep those observations separate when diagnosing a connection pool or an authentication gateway.

The case `role_connection_limit` passed on PostgreSQL 18.6 and the isolated PostgreSQL 10.21 target. The run IDs and per-case assertions are retained in the [public evidence JSON](../data/evidence/53300.json).

<!-- BEGIN SQLSTATE FACTS: generated by scripts/generate.py; do not edit -->

| Field | Value |
| --- | --- |
| SQLSTATE | `53300` |
| Condition | `too_many_connections` |
| Status | `active` |
| Known present by | `7.4` |
| Locked snapshots | `9.0.23, 9.1.24, 9.2.24, 9.3.25, 9.4.26, 9.5.25, 9.6.24, 10.23, 11.22, 12.22, 13.23, 14.24, 15.19, 16.15, 17.11, 18.6, 19beta3` |
| Macros | `ERRCODE_TOO_MANY_CONNECTIONS` |
| Aliases | `—` |

<!-- source facts: data/errcodes/53300.json -->
<!-- END SQLSTATE FACTS -->

## Meaning and trigger paths {#meaning}

During backend startup, PostgreSQL checks the authenticated role's `rolconnlimit` after creating the backend bookkeeping entry. For a non-superuser role with a nonnegative limit, a count above that limit raises `FATAL` with `ERRCODE_TOO_MANY_CONNECTIONS` and the message `too many connections for role "%s"`. The source comments describe this role count as approximate because simultaneous startups can race.

The same SQLSTATE can identify another capacity path, such as a server-wide client limit. The role-limit case here does not establish the cause of every `53300`; use the primary message, collector fields, and the configured role, database, and server limits to classify it.

Because the failure occurs before the SQL protocol reaches a transaction, transaction status is not `INERROR` or `IDLE` for the rejected session. A management or pool connection that remains open can change the limit and then prove recovery with a new session.

## Messages and diagnostics {#messages}

The executable excerpt uses the same role-limit SQL statements as the runner. `limited_user` is replaced by a disposable role in the isolated run. The second connection is a separate client-startup operation, so it is described between the SQL statements rather than represented by a fabricated SQL command.

<!-- BEGIN SQLSTATE SNIPPET: role_connection_limit -->
```sql
ALTER ROLE limited_user CONNECTION LIMIT 1;
-- Keep one session open as limited_user.
-- Open a second session as limited_user: startup returns FATAL 53300.
ALTER ROLE limited_user CONNECTION LIMIT -1;
SELECT 1;
```
<!-- END SQLSTATE SNIPPET -->

The latest target's collector record was:

```text
SQLSTATE: 53300                 # csvlog/jsonlog sql_state_code
severity: FATAL
message_primary: too many connections for role "<generated-role>"
source: miscinit.c / InitializeSessionUserId / line 880
driver startup sqlstate: null
transaction: none opened
repair: reset CONNECTION LIMIT; fresh role connection SELECT 1 -> 1
```

PostgreSQL 10.21 produced the same message and SQLSTATE in its collector, with the source location `miscinit.c:575`. In both targets the known role connection succeeded after the limit was reset. The role name and port above are run-generated values; the collector's `sql_state_code` is the server evidence. A startup error may not expose a SQLSTATE property through a particular driver.

## Diagnosis {#diagnosis}

Capture the connection parameters without secrets, the role and database, the server version, the exact startup text, and a collector record correlated by time, user, and connection source. Check `pg_roles.rolconnlimit`, database and server connection settings, and current backend counts. A pool can exhaust a role limit while the server still has global capacity.

Treat the role count as a capacity observation rather than an exact admission proof under a burst: PostgreSQL documents an approximate check for concurrent startups. Check the primary message before changing a global setting, and preserve an administrative path for recovery.

Do not issue transaction cleanup commands for the rejected session. It never reached a usable SQL transaction. A still-open owner or administration connection can restore the setting; the meaningful repair assertion is a fresh login for the affected role followed by a real query.

## Response and repair {#response}

- Bound pool size and connection concurrency so a role does not repeatedly exhaust its limit.
- Increase the role, database, or server capacity only after checking memory, workload, and the intended admission policy.
- Keep reserved capacity and a controlled administrative connection for recovery; do not grant superuser status merely to bypass a limit.
- After changing the limit, open a new connection and execute a harmless query. Reconcile pool state and close stale sessions before retrying application work.

The representative repair reset the disposable role's limit, opened a new role connection, and observed `SELECT 1` as `1`. That proves recovery of this role-limit path; it does not prove that a different database-wide or server-wide capacity failure has been repaired.

## Versions and boundaries {#versions}

The catalogue has a definition-presence observation for `53300` at PostgreSQL 7.4 and through the locked 8.4.22 pre-9.0 definitions, then in every listed formal snapshot through PostgreSQL 18.6 and the PostgreSQL 19 Beta 3 preview. This is a definition-only presence boundary, not an exact implementation introduction or runtime-use claim. The class title change between the 9.0 header and 9.1 text definitions is recorded in the catalogue; it is not an asserted implementation change for this condition.

The role-limit case passed on PostgreSQL 18.6 and 10.21. Source line numbers differ, and the driver/collector split is part of the observed boundary. Database-wide and server-wide capacity paths, connection pool behavior, and operating-system resource exhaustion require their own evidence.

## Related {#related}

[`28P01` — `invalid_password`](../28p01/) is another connection-startup failure with no SQL transaction. [`57014` — `query_canceled`](../57014/) is a statement interruption after a session has connected. [`42P01` — `undefined_table`](../42p01/) is a SQL name-resolution error after connection startup.

## Sources {#sources}

Structured evidence is recorded in the [public evidence JSON](../data/evidence/53300.json). Source records are fixed to PostgreSQL commit `724edf9bde9d356724ad384a2e196edc3c9f80f7`; runtime records retain the collector output, driver observation, both target IDs, and structured observations.

- `src.errcodes.18.6` — [`errcodes.txt`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/errcodes.txt#L407-L414)
- `src.miscinit.18.6` — [`miscinit.c`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/init/miscinit.c#L868-L880)
- `src.backend-startup.18.6` — [`backend_startup.c`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/tcop/backend_startup.c#L340-L344)
- `doc.protocol.18` — [Error and Notice Message Fields](https://www.postgresql.org/docs/18/protocol-error-fields.html)
- Runtime: `53300-registry-final-20260909` on latest and pg10; structured observations are in the [public evidence JSON](../data/evidence/53300.json)
