Un client e-commerce a subi un pic de trafic inattendu suite à une mention dans un média national, avec un afflux de visiteurs largement supérieur à ce que le site recevait habituellement. En quelques minutes, le site est devenu totalement inaccessible, affichant à la place un message d’erreur WordPress générique : « Error establishing a database connection ». Les journaux MySQL, eux, étaient plus précis : « Too many connections ».
Ce message signale que le serveur MySQL a atteint sa limite configurée de connexions simultanées (max_connections) et refuse toute nouvelle tentative de connexion, y compris celles d’un administrateur souhaitant se connecter pour diagnostiquer le problème — une situation particulièrement inconfortable en plein incident.
Diagnostic : distinguer une vraie saturation d’un pic ponctuel
La première étape consiste à se connecter avec un compte disposant du privilège SUPER, qui conserve une connexion de réserve même quand la limite générale est atteinte, précisément pour permettre ce type de diagnostic en urgence.
mysql -u root -p -e "SHOW STATUS LIKE 'Threads_connected';"
mysql -u root -p -e "SHOW VARIABLES LIKE 'max_connections';"
mysql -u root -p -e "SHOW PROCESSLIST;"
SHOW PROCESSLIST a révélé la cause précise : plus de cent-quarante connexions actives, dont l’écrasante majorité affichait l’état Sleep depuis plusieurs minutes — des connexions ouvertes par PHP-FPM, jamais fermées proprement, qui restaient comptabilisées dans la limite sans effectuer le moindre travail utile.
Comprendre pourquoi PHP-FPM accumule des connexions
Chaque processus PHP-FPM qui traite une requête WordPress ouvre sa propre connexion MySQL via mysqli ou PDO, utilisée le temps de la requête. En fonctionnement normal, cette connexion se ferme à la fin du script. Sous forte charge, avec un pool PHP-FPM dimensionné pour davantage de processus que la limite MySQL ne peut en accepter simultanément, chaque processus PHP ouvre sa connexion, et si le pool PHP dépasse la capacité MySQL, les connexions les plus anciennes ne se libèrent pas assez vite pour laisser la place aux nouvelles.

Le calcul qui avait été oublié à l’installation
Sur ce serveur, le pool PHP-FPM avait été dimensionné à 60 processus enfants (pm.max_children), une valeur cohérente avec la RAM disponible. Mais MySQL, installé avec sa configuration par défaut, conservait max_connections à 151 — une valeur standard, jamais revue lors du dimensionnement du reste de la pile. En théorie, 60 processus PHP ne devraient jamais dépasser 151 connexions ; en pratique, plusieurs autres services (un outil de supervision, un script de sauvegarde en cours d’exécution, une deuxième instance WordPress sur le même serveur mutualisé) consommaient eux aussi leur part de connexions au même moment, sans qu’aucun budget global n’ait été posé.
[mysqld]
max_connections = 300
wait_timeout = 60
interactive_timeout = 60
Deux réglages ont corrigé la situation durablement : une augmentation raisonnée de max_connections à 300, cohérente avec la RAM disponible pour MySQL, et une réduction du wait_timeout à 60 secondes, pour que les connexions Sleep abandonnées par des scripts mal terminés se referment plus rapidement plutôt que de s’accumuler pendant les 28800 secondes du défaut MySQL.
Correctif appliqué en urgence, puis en durable
Le correctif d’urgence, appliqué en quelques secondes sans redémarrage, ajuste la variable à chaud le temps de préparer une configuration pérenne :
SET GLOBAL max_connections = 300;
Cette modification à chaud ne survit pas à un redémarrage de MySQL : la valeur a ensuite été inscrite dans le fichier de configuration persistant pour devenir définitive.
Prévention : budgéter les connexions comme une ressource finie
- Additionner les connexions maximales théoriques de tous les services d’un serveur avant de fixer
max_connectionsau hasard - Réduire
wait_timeoutpour limiter la durée de vie des connexions abandonnées - Superviser
Threads_connecteden continu, avec une alerte avant d’atteindre la limite, pas après
Un pic de trafic ne devrait jamais faire tomber un site par manque de connexions disponibles : c’est un budget de ressources qui se calcule à froid, avant l’incident, jamais pendant.
En résumé
« Too many connections » n’indique presque jamais un problème de requêtes lentes, mais un déséquilibre entre le nombre de connexions que l’application peut ouvrir et ce que MySQL accepte réellement. Dimensionner cette limite en fonction de la charge applicative réelle évite qu’un simple pic de popularité ne se transforme en panne complète du site.