« Too many connections » — ce message MySQL, remonté dans les journaux d’erreur de plusieurs sites du réseau en même temps, a marqué le début d’un incident déclenché par une campagne d’inscription périscolaire ouverte simultanément sur les cinq cents sites d’un multisite WordPress mutualisé par une collectivité pour ses établissements scolaires.
Chaque établissement disposait de son propre site dans le réseau multisite, partageant la même base de données physique mais avec des tables préfixées séparément (wp_2_options, wp_3_options, etc.). L’ouverture simultanée du formulaire d’inscription à 8h précises, heure officielle de lancement communiquée aux familles, a concentré un afflux de connexions sur une fenêtre de quelques minutes.
Le mécanisme qui a mené à la saturation
Un multisite WordPress partage la même instance MySQL entre tous ses sites, mais chaque requête HTTP traitée par PHP-FPM ouvre sa propre connexion à la base de données, indépendamment du site du réseau qu’elle sert. Avec plusieurs centaines de familles connectées simultanément à des sites différents du réseau, chacune déclenchant plusieurs requêtes Ajax de vérification de disponibilité de créneau, le nombre de connexions simultanées a grimpé jusqu’à 512, dépassant la limite max_connections fixée à 400 dans la configuration MySQL du serveur.
Une fois cette limite atteinte, MySQL refuse purement et simplement toute nouvelle connexion, y compris pour des sites du réseau qui n’étaient pas directement concernés par la campagne d’inscription, provoquant un effet de bord sur l’ensemble du multisite plutôt qu’un ralentissement localisé.
Pourquoi augmenter simplement max_connections n’était pas suffisant

Le réflexe immédiat, augmenter max_connections dans my.cnf, a été envisagé puis écarté après calcul : chaque connexion MySQL consomme de la mémoire pour ses buffers de travail (tri, jointures temporaires), de l’ordre de plusieurs mégaoctets selon les réglages de sort_buffer_size et join_buffer_size. Multiplier la limite par deux ou trois aurait risqué de faire déborder la mémoire disponible du serveur en cas de nouveau pic, transformant un refus de connexion propre en un plantage du service MySQL entier.
La solution retenue : un pool de connexions partagé
ProxySQL a été installé en frontal de l’instance MySQL, avec un pool de connexions limité côté base de données mais capable de mettre en attente les requêtes excédentaires plutôt que de les rejeter brutalement :
# Extrait de configuration ProxySQL (mysql_servers et mysql_query_rules)
INSERT INTO mysql_servers(hostgroup_id, hostname, port, max_connections)
VALUES (0, '127.0.0.1', 3306, 350);
UPDATE global_variables SET variable_value='600'
WHERE variable_name='mysql-max_connections';
Ce réglage autorise jusqu’à 600 connexions côté applicatif (PHP-FPM), tout en limitant à 350 le nombre de connexions réellement ouvertes vers MySQL. Les requêtes excédentaires sont mises en file d’attente par ProxySQL, avec une latence supplémentaire de quelques dizaines à quelques centaines de millisecondes en cas de pic, plutôt qu’un rejet immédiat par un message d’erreur visible du visiteur.
Résultat lors de la campagne suivante
| Mesure | Sans ProxySQL | Avec ProxySQL |
|---|---|---|
| Connexions MySQL simultanées au pic | 512 (rejets au-delà de 400) | 348 (plafonné, file d’attente ProxySQL) |
| Erreurs « Too many connections » | Nombreuses, sur plusieurs sites | 0 |
| Latence médiane pendant le pic | Non mesurable (erreurs) | 640 ms |
Prévention pour les campagnes suivantes
- Un plafond de connexions MySQL doit être dimensionné en fonction de la mémoire disponible, jamais augmenté sans recalcul de la consommation mémoire totale possible.
- Un proxy de connexions absorbe un pic ponctuel sans changer la capacité réelle de la base ; il ne dispense pas d’un dimensionnement raisonnable en amont.
- Communiquer une heure de lancement précise à un grand nombre de familles concentre mécaniquement la charge ; étaler l’ouverture par ordre alphabétique d’établissement a été envisagé comme mesure complémentaire pour les campagnes suivantes.
Un pic de charge prévisible mérite un plan de charge, pas seulement une limite technique relevée au dernier moment.
En résumé
Ce dossier ne traite pas de la sécurité des formulaires d’inscription eux-mêmes, uniquement de la couche de connexion à la base de données mise sous tension par la concentration du trafic. Le pool de connexions partagé via ProxySQL a permis d’absorber un pic prévisible, structurel à ce type d’usage multisite, sans que chaque établissement scolaire n’ait eu à modifier quoi que ce soit à son propre site.