« Too many connections » dans Postgres : ce qui retient les connexions, et comment dimensionner le bassin.
Postgres refuse une nouvelle connexion quand toutes ses places sont prises, et garde les dernières pour les superutilisateurs : d’où le message « reserved ». Hausser la limite règle rarement le problème. Trouvez ce qui retient les connexions, plafonnez le bassin de chaque processus et ajoutez un regroupeur seulement si plusieurs processus partagent une base.
Faits vérifiés le
Quel message vous avez reçu, et ce qui est plein
On appelle « trop de connexions » deux choses différentes. Soit le serveur de base de données n’a plus de places, soit le bassin de votre appli n’a plus de connexion libre et une requête a cessé d’attendre. Les correctifs diffèrent : lisez d’abord le texte exact.
| Message | Qui le produit | Ce qui est plein |
|---|---|---|
FATAL: sorry, too many clients already † | Postgres | Toutes les places jusqu’à max_connections (100 par défaut) sont prises. |
remaining connection slots are reserved for non-replication superuser connections † † | Postgres 15 et moins | Il ne reste que les places superuser_reserved_connections (3 par défaut), et votre appli n’est pas superutilisateur. |
remaining connection slots are reserved for roles with the SUPERUSER attribute † † | Postgres 16 et plus | La même chose, nouvelle formulation. |
remaining connection slots are reserved for roles with privileges of the "pg_use_reserved_connections" role † † | Postgres 16 et plus, quand reserved_connections dépasse 0 (0 par défaut) | Il ne reste que les places réservées supplémentaires. |
ActiveRecord::ConnectionTimeoutError - could not obtain a database connection within 5.000 seconds † | Rails | Le bassin de Rails, pas le serveur. Plus de fils veulent une connexion que pool n’en permet. |
P2024: Timed out fetching a new connection from the connection pool † | Prisma 6 et moins | Le bassin de Prisma. Voir Prisma P2024. |
timeout exceeded when trying to connect † | node-postgres (pg) | Le pg.Pool, une fois connectionTimeoutMillis défini (par défaut, il attend indéfiniment). |
| Client déconnecté après une attente † | PgBouncer | Aucune connexion serveur ne s’est libérée pendant query_wait_timeout (120 secondes par défaut). |
† Les détails sur les concurrents proviennent des pages publiées par chaque fournisseur aux dates indiquées; les prix et forfaits changent, vérifiez auprès du fournisseur avant de décider. `FATAL: sorry, too many clients already` (2026-10-29) · `remaining connection slots are reserved for non-replication superuser connections` (2026-10-29) · `remaining connection slots are reserved for non-replication superuser connections` (2026-10-29) · `remaining connection slots are reserved for roles with the SUPERUSER attribute` (2026-10-29) · `remaining connection slots are reserved for roles with the SUPERUSER attribute` (2026-10-29) · `remaining connection slots are reserved for roles with privileges of the "pg_use_reserved_connections" role` (2026-10-29) · `remaining connection slots are reserved for roles with privileges of the "pg_use_reserved_connections" role` (2026-10-29) · `ActiveRecord::ConnectionTimeoutError - could not obtain a database connection within 5.000 seconds` (2026-10-29) · `P2024: Timed out fetching a new connection from the connection pool` (2026-10-29) · `timeout exceeded when trying to connect` (2026-10-29) · Client déconnecté après une attente (2026-10-29)
Trouver ce qui retient les connexions
Connectez-vous avec psql et regardez avant de changer quoi que ce soit. pg_stat_activity contient une ligne par connexion. Une ligne à l’état idle est une connexion qui dort dans un bassin. idle in transaction est pire : une transaction a été ouverte sans jamais être validée, et elle retient aussi des verrous.
- Beaucoup de lignes `idle` pour un même `application_name` : un bassin trop grand, ou un processus qui crée un bassin à chaque requête. Plafonnez le bassin (plus bas) et créez-le une seule fois au démarrage.
- Des lignes de processus oubliés : un ancien déploiement, un aperçu, un processus de tâches, un carnet Jupyter, un outil de BI resté ouvert. Chacun garde son propre bassin.
- `idle in transaction` pendant des minutes : un chemin de code qui ouvre une transaction et sort trop tôt, ou un débogueur arrêté en pleine requête. Corrigez le code, et réglez
idle_in_transaction_session_timeoutpour que Postgres y mette fin lui-même. - Beaucoup de lignes `active`, toutes lentes : les connexions travaillent, elles ne fuient pas. Plus de connexions n’aideront pas; des requêtes plus rapides, oui. Voir trouver les requêtes lentes.
-- Who holds connections to this database, and doing what
SELECT usename, application_name, state, count(*) AS conns,
max(now() - state_change) AS longest_in_state
FROM pg_stat_activity
WHERE datname = current_database()
AND backend_type = 'client backend'
GROUP BY 1, 2, 3
ORDER BY conns DESC;
-- Sessions stuck inside an open transaction
SELECT pid, usename, application_name, now() - state_change AS stuck_for, left(query, 80) AS last_query
FROM pg_stat_activity
WHERE state = 'idle in transaction'
ORDER BY stuck_for DESC;Le calcul du bassin pour une petite appli
Chaque processus qui parle à la base garde son propre bassin, et toutes ses connexions peuvent être ouvertes en même temps. Le nombre qui doit tenir sous la limite du serveur est la somme de tous les processus :
(processus web × connexions par processus) + (processus de tâches × connexions par processus) + commande de mise en production ou migrations + tout le reste qui se connecte (aperçus, `psql`, outils de BI)
Une connexion par fil suffit. Un processus Puma à 3 fils n’a jamais besoin de plus de 3 connexions pour les requêtes. Donnez-lui-en plus et elles dorment. Donnez-lui-en moins et les fils font la file, d’où l’expiration de Rails plus haut.
# Rails (config/database.yml). Rails 8.1 also accepts max_connections:
production:
url: <%= ENV["DATABASE_URL"] %>
pool: <%= ENV.fetch("DB_POOL", 6) %> # 3 Puma threads + 3 job threads
// Node (pg): one Pool per process, created once at startup
const pool = new pg.Pool({ connectionString: process.env.DATABASE_URL, max: 8 });
# Django: persistent connections, one per worker thread
DATABASES["default"]["CONN_MAX_AGE"] = 600
# SQLAlchemy: cap the overflow too, or 5 becomes 15
engine = create_engine(url, pool_size=5, max_overflow=2)| Pile | Ce qui fixe les connexions par processus | Par défaut |
|---|---|---|
| Rails + Puma † † † | pool dans database.yml (renommé max_connections dans Rails 8.1; pool fonctionne encore) | Configuration générée : RAILS_MAX_THREADS, ou 5. Le puma.rb des nouvelles applis roule 3 fils et 1 processus. |
| Django † | Une connexion par fil de travail. CONN_MAX_AGE la garde ouverte; Django 5.1+ peut regrouper avec "pool": True (psycopg 3) | CONN_MAX_AGE = 0 : fermée après chaque requête |
| SQLAlchemy † | pool_size + max_overflow | 5 + 10, donc jusqu’à 15 par processus; attente de 30 s |
Node (pg) † | max sur pg.Pool | 10; aucun délai d’acquisition |
| Prisma † † | v6 : connection_limit dans l’URL. v7 : le bassin de l’adaptateur de pilote (max pour pg) | v6 : processeurs physiques × 2 + 1. v7 avec pg : 10 |
| Base Canner | Plafond par base | Jusqu’à 20 connexions ouvertes en même temps |
† Les détails sur les concurrents proviennent des pages publiées par chaque fournisseur aux dates indiquées; les prix et forfaits changent, vérifiez auprès du fournisseur avant de décider. Rails + Puma (2026-10-29) · Rails + Puma (2026-10-29) · Rails + Puma (2026-10-29) · Django (2026-10-29) · SQLAlchemy (2026-10-29) · Node (`pg`) (2026-10-29) · Prisma (2026-10-29) · Prisma (2026-10-29)
Exemple concret : tenir sous 20
Une base Canner accepte jusqu’à 20 connexions en même temps (documentation des tâches en arrière-plan). Un projet exécute un seul processus, donc le budget se calcule facilement. Un projet worker distinct branché sur la même base compte dans les mêmes 20 :
- Rails avec GoodJob dans le processus web : 3 fils Puma + 3 fils de tâches + 3 pour l’écoute et l’entretien de GoodJob = 9. L’exemple de la documentation fixe
DB_POOLà 12, ce qui laisse 8. - Node avec un seul `pg.Pool` : le
maxpar défaut de 10 prend la moitié du budget. Un déploiement d’aperçu de la même appli est un autre processus, avec le mêmeDATABASE_URLet 10 de plus. Réglezmax: 8et les deux entrent, avec de la place pourpsql. - Prisma 6 : la valeur par défaut dépend du nombre de processeurs que voit le processus, pas de votre forfait. Sur un hôte à 8 cœurs physiques, ça donne 17. Fixez
connection_limitvous-même. - La commande de mise en production : les migrations roulent pendant que la version actuelle sert encore; gardez une ou deux connexions de marge.
Pourquoi hausser max_connections vient en dernier
Chaque connexion Postgres est un processus serveur distinct, avec sa propre mémoire. Une fois le processeur et le disque occupés, plus de connexions n’ajoutent que de la contention. La règle empirique du wiki de PostgreSQL pour les connexions actives est (core_count × 2) + effective_spindle_count, un chiffre bien plus petit que ce qu’on imagine.
max_connections exige aussi un redémarrage du serveur. Sur une base gérée, on ne peut généralement pas le régler : le fournisseur le dimensionne selon la mémoire. Si vous êtes à la limite à cause de connexions inactives, des bassins plus petits règlent le problème gratuitement.
PgBouncer : mode session ou mode transaction
Un regroupeur de connexions se place entre l’appli et Postgres et distribue les connexions serveur. Ce qu’il peut partager dépend du mode. En mode session (le mode par défaut de PgBouncer), un client garde une connexion serveur jusqu’à ce qu’il se déconnecte. Rien ne casse, et rien n’est partagé : 20 clients ouverts exigent encore 20 connexions serveur. En mode transaction, la connexion serveur retourne au bassin à la fin de chaque transaction; des centaines de clients surtout inactifs peuvent alors se partager quelques connexions. Le prix : tout ce qui dépend d’une session cesse de fonctionner.
- Prenez le mode transaction quand beaucoup de processus éphémères ou sans serveur ouvrent chacun des connexions. Désactivez alors ce qui dépend d’une session :
DISABLE_SERVER_SIDE_CURSORS = Truedans Django,pgbouncer=truesur l’URL regroupée de Prisma avec une URL directe pour les migrations, etadvisory_locks: falsepour les migrations Rails. - Restez en mode session pour un ou quelques processus de longue durée, et pour tout ce qui repose sur
LISTEN/NOTIFYou les verrous consultatifs : GoodJob, verrous de migration, files de tâches dans Postgres.
| Fonction | Mode session | Mode transaction |
|---|---|---|
SET / RESET † | Oui | Jamais |
LISTEN † | Oui | Jamais (NOTIFY fonctionne) |
| Verrous consultatifs de session † | Oui | Jamais |
PREPARE / DEALLOCATE en SQL † | Oui | Jamais (les requêtes préparées au niveau du protocole fonctionnent avec max_prepared_statements) |
Curseurs WITH HOLD, LOAD † | Oui | Jamais |
† Les détails sur les concurrents proviennent des pages publiées par chaque fournisseur aux dates indiquées; les prix et forfaits changent, vérifiez auprès du fournisseur avant de décider. `SET` / `RESET` (2026-10-29) · `LISTEN` (2026-10-29) · Verrous consultatifs de session (2026-10-29) · `PREPARE` / `DEALLOCATE` en SQL (2026-10-29) · Curseurs `WITH HOLD`, `LOAD` (2026-10-29)
Quand ce plafond ne convient pas
Canner exécute un processus par projet et permet jusqu’à 20 connexions par base, partagées avec tout projet worker distinct qui s’y branche. Ça convient à une appli web dont les tâches roulent dans le même processus. Si votre architecture a besoin de dizaines d’instances distinctes ou de fonctions sans serveur qui parlent à la même base en même temps, il vous faut un regroupeur en mode transaction devant un serveur dimensionné pour ça, et Canner ne l’offre pas aujourd’hui.
Questions
Quelle différence entre « sorry, too many clients already » et « remaining connection slots are reserved »?
Les deux veulent dire que le serveur n’a plus de place pour vous. « Reserved » apparaît d’abord, quand il ne reste que les places gardées pour les superutilisateurs (3 par défaut). « Sorry, too many clients already » veut dire que toutes les places jusqu’à max_connections sont prises.
Faut-il simplement hausser max_connections?
Généralement non. La plupart des incidents de « trop de connexions » viennent de connexions inactives dans des bassins trop grands, ou de processus oubliés. Chaque connexion coûte de la mémoire et, une fois le processeur occupé, en ajouter ralentit tout. Réduisez d’abord les bassins.
Combien de connexions faut-il à une appli Rails avec Puma?
Une par fil qui peut toucher la base : fils Puma × processus Puma, plus les fils de tâches si les tâches roulent dans le même processus, plus quelques-unes pour l’écoute de la bibliothèque de tâches. Les nouvelles applis Rails roulent 3 fils Puma et 1 processus.
PgBouncer règle-t-il le problème de trop de connexions?
En mode transaction, oui : beaucoup de clients se partagent peu de connexions serveur, au prix des fonctions de session comme les verrous consultatifs et LISTEN. En mode session, il ne réduit pas le nombre; chaque client garde une connexion serveur.
Combien de connexions une base Canner permet-elle?
Jusqu’à 20 ouvertes en même temps par base, chacune avec sa propre session Postgres. Dimensionnez vos bassins en conséquence, en comptant les fils web, les fils de tâches, les aperçus et tout ce que vous y connectez.
Une base Postgres avec chaque projet.
Des connexions de session : les verrous consultatifs et LISTEN fonctionnent. Comparez les forfaits sur la page des prix.