PostgreSQL FATAL: remaining connection slots are reserved
Encountering "FATAL: remaining connection slots are reserved" means your PostgreSQL database has hit its max_connections limit; this guide explains how to fix it.
What This Error Means
This error message, FATAL: remaining connection slots are reserved, indicates a critical state in your PostgreSQL database. It means that the database server has reached its configured maximum number of concurrent connections (max_connections), and critically, even the reserved slots for superusers are now in use or unreachable.
PostgreSQL reserves a small number of connection slots (typically 2-4) for superusers by default. This is a safeguard, allowing an administrator to connect and troubleshoot even when the database is overwhelmed with regular user connections. When you see this specific FATAL error, it signifies that not only have all regular connection slots been exhausted, but these superuser slots are also either already in use, or the server is so resource-starved that it cannot even accept new superuser connections. Essentially, your database is effectively unreachable for new connections, preventing applications and even administrators from connecting.
Why It Happens
PostgreSQL allocates a certain amount of memory and other resources for each active connection. The max_connections parameter is a crucial configuration setting that limits the total number of concurrent client connections the PostgreSQL server will accept. This limit is in place to prevent the server from becoming overloaded, exhausting its system resources (like RAM or CPU), and potentially crashing.
When the number of incoming connection requests exceeds the max_connections limit, PostgreSQL rejects any new connection attempts. If the server is still somewhat functional, it might respond with a less severe message indicating max_connections was reached. However, the FATAL: remaining connection slots are reserved message usually points to a more dire situation where the server is completely saturated or struggling significantly, indicating a severe resource bottleneck or a runaway process consuming all available slots.
In my experience, this often points to an application misconfiguration or an unexpected spike in demand that the current database sizing or configuration cannot handle.
Common Causes
Identifying the root cause is the first step to a lasting fix. Here are the most common culprits I've encountered that lead to this FATAL error:
- Insufficient
max_connections: The simplest cause is that the configuredmax_connectionsvalue inpostgresql.confis simply too low for your application's actual needs or current workload. As applications scale or traffic increases, this value often needs adjustment. - Lack of Connection Pooling (or Misconfigured Pooling):
- No Pooling: Applications that establish a new database connection for every single request, without reusing them, are prime candidates for quickly exhausting
max_connections. - Misconfigured Pool: Even with a connection pool, if the pool's
max_sizeis set too high (e.g., greater thanmax_connectionsor if multiple application instances each have large pools), it can collectively overwhelm the database.
- No Pooling: Applications that establish a new database connection for every single request, without reusing them, are prime candidates for quickly exhausting
- Unclosed Connections/Connection Leaks: Application code that opens database connections but fails to close them properly (e.g., due to unhandled exceptions, incorrect
finallyblocks, or poor resource management) will lead to an accumulation of "leaked" connections that never return to the pool or are released, eventually consuming all available slots. I've seen this in production when developers forget to properly manage resource lifecycles. - Long-Running Queries or Transactions: Queries or transactions that take an unusually long time to complete can hold connections open for extended periods, reducing the availability of slots for other incoming requests. This is especially problematic with heavy analytical queries run during peak operational hours.
- Spikes in Application Traffic: Sudden, unexpected bursts of user activity or background jobs (e.g., batch processing, report generation) can temporarily drive up the demand for database connections beyond the server's capacity.
- Idle but Active Connections: Connections that are "idle in transaction" (e.g., waiting for user input within a transaction) or simply idle but not explicitly closed can still hold a connection slot, preventing new connections. While
idleconnections are usually fine,idle in transactioncan be a problem. - External Monitoring Tools: Sometimes, aggressive monitoring tools or health checks that open and close connections frequently can contribute, especially if they are not correctly configured.
Step-by-Step Fix
Addressing this FATAL error requires a combination of immediate relief (if possible) and long-term configuration changes. Always proceed with caution, especially when modifying production systems.
Step 1: Immediate Diagnosis (If Superuser Access is Possible)
If you can still connect as a superuser (e.g., postgres user) to the database, even briefly, you can gather crucial information. Sometimes, the reserved slots are still functional, allowing you to peek in.
-
Check Current Connections:
sql SELECT pid, usename, application_name, client_addr, backend_start, state, query_start, state_change, wait_event_type, wait_event FROM pg_stat_activity WHERE state IS NOT NULL AND pid <> pg_backend_pid() ORDER BY backend_start;
Look for a high number of active or idle connections, especially from specificapplication_nameorclient_addr. This query helps identify connection leaks or problematic applications. -
Check
max_connections:
sql SHOW max_connections;
Note down the current configured limit. -
Check PostgreSQL Logs:
The PostgreSQL server logs (typically found in/var/log/postgresql/or your data directory'slogsubdirectory) will contain numerous entries related to connections being refused due tomax_connections. Look for timestamped entries around the time the issue started. This can also reveal which applications are trying to connect.
Step 2: Emergency Connection Termination (Use with Extreme Caution!)
If you can connect as a superuser and identify specific idle or problematic connections that are not critical, you can terminate them to free up slots. This is a temporary measure to gain access and should not be a regular solution.
SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE usename = 'problem_user' AND state = 'idle';
Replace 'problem_user' with the actual username identified in pg_stat_activity. Be extremely careful, terminating active connections can lead to data inconsistencies or application failures. Only terminate idle connections if you're sure.
Step 3: Increase max_connections (Primary Fix)
This is often the most direct way to resolve the issue, but it comes with a caveat: increasing max_connections consumes more RAM. Each connection requires a certain amount of shared buffer, work memory, and other resources.
-
Locate
postgresql.conf:
The configuration file is typically found in your PostgreSQL data directory (e.g.,/etc/postgresql/14/main/postgresql.confon Debian/Ubuntu, or/var/lib/pgsql/data/postgresql.confon CentOS/RHEL). You can find its location by connecting to PostgreSQL and runningSHOW config_file;. -
Edit
postgresql.conf:
Open the file with a text editor (e.g.,sudo nano /etc/postgresql/14/main/postgresql.conf).
Find the linemax_connections = 100(or whatever value is set).
Increase this value. A common starting point might be 200, 300, or even more, depending on your server's resources and application demand. A general rule of thumb is to allow for your application's max pool size plus some overhead for admin tools, but not so much that you exhaust system RAM.```ini
postgresql.conf snippet
max_connections = 200 # increased from 100
```Self-Correction: Remember to also review
shared_buffers,work_mem, andmaintenance_work_memwhen significantly increasingmax_connections, as these parameters directly impact memory usage per connection. -
Restart PostgreSQL:
Changes tomax_connectionsrequire a full database restart to take effect.
Onsystemd-based systems (most modern Linux distributions):
bash sudo systemctl restart postgresql # Or for a specific version: sudo systemctl restart postgresql@14-main
On macOS with Homebrew:
bash brew services restart postgresql
Forpg_ctl:
bash pg_ctl restart -D /path/to/your/data/directory
After the restart, verify the newmax_connectionsvalue usingSHOW max_connections;.
Step 4: Implement or Tune Connection Pooling
This is a critical long-term solution.
- Application-Side Pooling: Most modern application frameworks (e.g., Spring Boot with HikariCP, Node.js with
pgmodule andnode-postgres-pool, Python withpsycopg2andconn_pool) have built-in connection pooling. Ensure it's enabled and configured correctly.- Set a reasonable
max_pool_sizefor your application instances. The sum of all application pool sizes should ideally not exceedmax_connections.
- Set a reasonable
- External Connection Poolers: For more complex environments or multiple applications connecting to the same database, consider using an external connection pooler like PgBouncer or Pgpool-II. These tools sit between your applications and PostgreSQL, multiplexing connections and presenting a much smaller, stable number of connections to the database, significantly reducing the load.
Step 5: Optimize Application Code and Queries
Review application code for connection leaks. Profile queries to identify long-running ones and optimize them using better indexes, query rewrites, or by scheduling them during off-peak hours.
Code Examples
Here are some concise, copy-paste ready code examples for diagnosis and modification:
-
Check current
max_connections:
sql SHOW max_connections; -
List all active and idle connections (excluding your own session):
sql SELECT pid, usename, application_name, client_addr, backend_start, state, query_start, state_change, wait_event_type, wait_event FROM pg_stat_activity WHERE state IS NOT NULL AND pid <> pg_backend_pid() ORDER BY backend_start; -
Terminate a specific backend process (replace
<PID>with the actual process ID):
sql SELECT pg_terminate_backend(12345);
(Always verify the PID first and ensure it's not a critical process.) -
Example
postgresql.confmodification (increasemax_connections):
```ini
#------------------------------------------------------------------------------
# CONNECTIONS AND AUTHENTICATION
#------------------------------------------------------------------------------- Connection Settings -
listen_addresses = '' # what IP address(es) to listen on;
# comma-separated list of addresses;
# defaults to 'localhost'; use '' for all
# (change requires restart)
port = 5432 # (change requires restart)
max_connections = 250 # (change requires restart)
# (normally 100 or less; too high may cause memory
# exhaustion problems)
``` -
Restart PostgreSQL service on Linux (using
systemd):
bash sudo systemctl restart postgresql
or for a specific version:
bash sudo systemctl restart postgresql@15-main
Environment-Specific Notes
The approach to managing max_connections can vary significantly based on your deployment environment.
Cloud Providers (AWS RDS, GCP Cloud SQL, Azure Database for PostgreSQL)
- Configuration: You cannot directly edit
postgresql.confon these managed services. Instead, you modifymax_connectionsvia their respective console, CLI, or API.- AWS RDS: Use "Parameter Groups." You'll likely need to create a custom parameter group, modify
max_connectionsthere, and then apply it to your DB instance. - GCP Cloud SQL: Edit the instance configuration, specifically the "Database flags" or "Parameters."
- Azure Database for PostgreSQL: Use the "Server parameters" blade in the Azure portal.
- AWS RDS: Use "Parameter Groups." You'll likely need to create a custom parameter group, modify
- Restart: Applying parameter group changes or database flags often requires a scheduled maintenance window or an immediate database restart via the cloud provider's console.
- Scaling: Cloud environments often automatically scale
max_connectionsbased on instance size (e.g., more RAM usually means a higher defaultmax_connections). If you hit this limit frequently, consider scaling up your database instance (e.g., to a larger instance type with more RAM and CPU).
Docker / Containerized Environments
- Configuration:
- Environment Variables: For simple Docker setups, you can often pass
max_connectionsas an environment variable to the PostgreSQL container, especially if using an official image. For example, indocker-compose.yml:
yaml services: db: image: postgres:15 environment: POSTGRES_DB: mydb POSTGRES_USER: user POSTGRES_PASSWORD: password PGDATA: /var/lib/postgresql/data/pgdata # Set max_connections via command or entrypoint script POSTGRES_INITDB_ARGS: "--max-connections=200" # Not directly for max_connections, but for other init flags command: ["postgres", "-c", "max_connections=250"] # This is how I usually set it - Custom
postgresql.conf: For more control, mount a custompostgresql.conffile into the container at/etc/postgresql/postgresql.confor/var/lib/postgresql/data/postgresql.conf.
- Environment Variables: For simple Docker setups, you can often pass
- Restart: A simple
docker restart <container_id>ordocker-compose restart dbwill apply the changes. - Orchestration: In Kubernetes,
max_connectionswould typically be managed via a ConfigMap that's mounted as a volume, or set through environment variables specified in the Deployment manifest.
Local Development Environment
- Configuration: You'll typically be directly editing the
postgresql.conffile as described in Step 3. - Restart: Use your local system's service manager (
brew services restart postgresqlon macOS,sudo systemctl restart postgresqlon Linux, orpg_ctldirectly). - Troubleshooting: Local environments are great for quickly reproducing and testing changes without affecting production, but they often have fewer resources. Keep
max_connectionsreasonable.
Frequently Asked Questions
Q: Can I increase max_connections indefinitely to solve this problem?
A: No, increasing max_connections too much can lead to severe performance degradation and even instability. Each connection consumes system resources (primarily RAM, but also CPU and file descriptors). If you set it too high, your server might run out of memory and crash, or become extremely slow due to excessive context switching and memory swapping. Always balance the max_connections setting with your server's available RAM and CPU.
Q: What's a good value for max_connections?
A: There's no one-size-fits-all answer. It highly depends on your server's hardware, workload, and whether you're using connection pooling. For a dedicated database server, values between 100-500 are common. If you use a robust external connection pooler like PgBouncer, you might keep max_connections on the PostgreSQL server relatively low (e.g., 50-100) as PgBouncer will manage the high volume of client connections. Monitor your system's memory and CPU usage after increasing the value.
Q: How do connection pools help prevent this error?
A: Connection pools are crucial. Instead of each application request opening and closing a new database connection, the pool maintains a fixed set of open connections. When the application needs a connection, it "borrows" one from the pool. When done, it "returns" it. This significantly reduces the overhead of connection establishment and, more importantly, limits the maximum number of concurrent connections from the application to the database to the pool's configured size, effectively preventing connection storms that could exhaust max_connections.
Q: Why does PostgreSQL reserve connection slots for superusers?
A: This is a vital fail-safe mechanism. Even when your database is completely overwhelmed by regular connections, the reserved superuser slots (controlled by the superuser_reserved_connections parameter, default usually 2-4) allow an administrator to connect using a superuser role (like postgres). This access enables them to diagnose the problem, terminate problematic connections, or make configuration changes to bring the database back to a healthy state, without needing to fully restart the server immediately. The FATAL error means even these slots are now effectively unavailable.
Q: Does using an external connection pooler like PgBouncer or Pgpool-II solve this problem permanently?
A: External connection poolers are an excellent solution for managing and multiplexing connections, and they can significantly mitigate the max_connections issue. By sitting in front of PostgreSQL, they accept many client connections but maintain only a smaller, fixed number of connections to the actual database server. This offloads connection management from PostgreSQL and reduces its resource consumption. However, they don't solve underlying issues like poorly optimized queries or genuine resource bottlenecks if your max_connections is already very high and the server is struggling. They are a powerful tool, not a magic bullet.
Related Errors
*() *