WordPress « Erreur lors de l’établissement d’une connexion à la base de données » : récupération rapide et prévention

Cet article vous a aidé ?

La page est blanche. Ou pire : elle s’affiche instantanément avec cette unique ligne qui fait soupirer tout ingénieur en astreinte — « Error establishing a database connection. » Votre CEO actualise la page. L’équipe marketing « vérifie juste un truc ». Votre monitoring crie comme une bouilloire.

Cette erreur n’est pas un diagnostic. C’est WordPress qui dit : « J’ai posé une question à la base de données et je n’ai eu aucun bruit en retour. » Votre travail consiste à déterminer si ce silence signifie une base de données morte, une adresse incorrecte, un problème d’identifiants, un serveur saturé ou un sous-système de stockage qui se détériore en silence.

Ce que l’erreur signifie vraiment (et ce qu’elle ne signifie pas)

WordPress affiche « Error establishing a database connection » lorsqu’il ne peut pas compléter sa négociation de connexion initiale vers MySQL/MariaDB (ou un autre serveur compatible MySQL). L’échec intervient avant que WordPress puisse exécuter des requêtes pour les options, les utilisateurs ou les articles, d’où l’absence de thème, de contenu, et seulement ce message.

Techniquement, WordPress fait quelque chose comme :

  • Lire les réglages DB depuis wp-config.php (DB_NAME, DB_USER, DB_PASSWORD, DB_HOST).
  • Initialiser le pilote client de la base de données (mysqli).
  • Ouvrir une connexion TCP (typiquement port 3306) ou un socket local.
  • S’authentifier.
  • Sélectionner le schéma de la base.

Si l’une de ces étapes échoue, le rendu est identique. C’est pourquoi les récupérations les plus rapides commencent par réduire le domaine de défaillance : réseau vs processus vs identifiants vs saturation vs stockage.

Ce que ce n’est pas : généralement pas un « bug WordPress ». WordPress n’est que le messager. Parfois le messager est agaçant, mais le message reste utile.

Deux schémas communs :

  1. Arrêt dur : le service de base est arrêté, planté ou inaccessible. La correction est d’ordre opérationnel.
  2. Arrêt mou : la base est en vie mais refuse les connexions (trop de clients, stockage lent, contention de verrous, problème DNS, problème d’authentification). La correction est souvent liée à la capacité ou à la configuration.

Une citation à coller dans votre processus d’incident :

« L’espoir n’est pas une stratégie. » — General Gordon R. Sullivan

Playbook de diagnostic rapide (premier/deuxième/tiers)

Quand votre site est indisponible, « être exhaustif » est la manière de rater votre SLA. Soyez rapide, puis exhaustif. Voici l’ordre qui gagne en production.

Premier : confirmer ce qui est cassé depuis l’extérieur

  1. Accédez au site depuis un chemin réseau propre (pas votre VPN de bureau) et confirmez que ce n’est pas une couche de cache qui sert une page d’erreur obsolète.
  2. Vérifiez si /wp-admin/ affiche la même erreur. Si oui, ce n’est pas le rendu du thème ; c’est l’initialisation DB précoce.
  3. Consultez les tableaux de bord de santé des serveurs (CPU, load, mémoire, latence disque). Si la latence disque augmente fortement, considérez la base de données comme suspecte jusqu’à preuve du contraire.

Deuxième : isoler réseau vs service

  1. Si la DB est distante : testez la connectivité TCP vers le port 3306 depuis l’hôte web.
  2. Si la DB est locale : vérifiez que le socket Unix existe et que MySQL écoute.
  3. Validez la résolution DNS pour DB_HOST si c’est un nom d’hôte, pas une IP.

Troisième : identifiants et capacité

  1. Vérifiez que wp-config.php correspond aux identifiants et à l’hôte réels de la DB.
  2. Vérifiez MySQL pour « Too many connections », requêtes lentes ou récupération InnoDB.
  3. Consultez les logs : PHP-FPM, Nginx/Apache, log d’erreur MySQL et journal système.

Règle pratique : si vous pouvez vous connecter avec les mêmes identifiants depuis le serveur web, WordPress le peut aussi. Si vous ne le pouvez pas, arrêtez d’éditer WordPress et réparez la plateforme.

Blague #1 : La base de données n’est pas « en congé », elle prend juste un jour personnel — juste après que vous ayez commencé le vôtre.

Tâches pratiques de récupération (commandes, sorties, décisions)

Ci‑dessous des tâches pratiques à exécuter pendant un incident. Chacune inclut : une commande, ce que signifie la sortie, et la décision suivante. C’est ce que vous faites vraiment à 02:17.

Task 1: Confirm MySQL/MariaDB service status

cr0x@server:~$ sudo systemctl status mariadb --no-pager
● mariadb.service - MariaDB 10.11.6 database server
     Loaded: loaded (/lib/systemd/system/mariadb.service; enabled; preset: enabled)
     Active: active (running) since Thu 2025-12-26 01:58:12 UTC; 15min ago
       Docs: man:mariadbd(8)
             https://mariadb.com/kb/en/library/systemd/
   Main PID: 2143 (mariadbd)
     Status: "Taking your SQL requests now..."
      Tasks: 37 (limit: 18956)
     Memory: 1.2G
        CPU: 2min 41.121s
     CGroup: /system.slice/mariadb.service
             └─2143 /usr/sbin/mariadbd

Sens : Si c’est active (running), le démon DB existe. Cela ne signifie pas qu’il accepte les connexions, mais il est en vie.

Décision : Si inactive, failed ou en redémarrage, passez aux logs (Tâche 4) et aux vérifications de stockage (Tâches 11/12) avant de redémarrer aveuglément.

Task 2: See if MySQL is listening on the expected interface/port

cr0x@server:~$ sudo ss -lntp | grep -E ':(3306|33060)\b'
LISTEN 0      151          127.0.0.1:3306        0.0.0.0:*    users:(("mariadbd",pid=2143,fd=22))

Sens : Cette DB n’écoute que sur localhost. Si votre WordPress est sur un autre hôte, il échouera à chaque fois.

Décision : Si WordPress est distant, corrigez bind-address ou utilisez un écouteur réseau privé. Si local, assurez-vous que DB_HOST pointe vers 127.0.0.1 ou vers le socket correctement.

Task 3: Verify DNS resolution for DB_HOST

cr0x@server:~$ getent hosts db.internal
10.10.2.15      db.internal

Sens : Le nom se résout. S’il bloque ou ne retourne rien, vous avez un problème DNS ou de résolveur (fréquent lors d’incidents réseau).

Décision : Si cassé, épinglez temporairement via une entrée /etc/hosts pendant l’atténuation de l’incident, puis corrigez DNS proprement après.

Task 4: Check the database error log for crash recovery, corruption, or disk issues

cr0x@server:~$ sudo tail -n 60 /var/log/mysql/error.log
2025-12-26 02:10:44 0 [Note] InnoDB: Starting crash recovery.
2025-12-26 02:10:44 0 [Note] InnoDB: 128 out of 128 rollback segments are active.
2025-12-26 02:10:47 0 [Note] InnoDB: Crash recovery finished.
2025-12-26 02:10:47 0 [Warning] Aborted connection 431 to db: 'wpdb' user: 'wpuser' host: '10.10.3.21' (Got timeout reading communication packets)

Sens : Une récupération après crash a eu lieu (donc il y a eu un crash ou un arrêt non propre). Des connexions avortées suggèrent des timeouts ou des blocages réseau.

Décision : Si la récupération boucle ou montre des erreurs I/O, cessez d’accuser WordPress. Vérifiez la latence du stockage et la santé du système de fichiers (Tâches 11–12).

Task 5: Test connectivity from the web server using the same credentials as WordPress

cr0x@server:~$ grep -E "DB_(NAME|USER|PASSWORD|HOST)" /var/www/html/wp-config.php
define('DB_NAME', 'wpdb');
define('DB_USER', 'wpuser');
define('DB_PASSWORD', 'correcthorsebatterystaple');
define('DB_HOST', 'db.internal');

cr0x@server:~$ mysql -h db.internal -u wpuser -p -e "SELECT 1;"
Enter password:
1
1

Sens : Si cela réussit, réseau + identifiants sont OK. WordPress devrait pouvoir se connecter, donc le problème est probablement le runtime PHP, un décalage de socket ou une saturation transitoire.

Décision : Si cela échoue, le message d’erreur de mysql est en or — agissez en conséquence. « Access denied » signifie identifiants/permissions. « Can’t connect » signifie réseau/écoute/firewall. « Unknown MySQL server host » signifie DNS.

Task 6: Check whether MySQL is refusing due to max_connections

cr0x@server:~$ mysql -h db.internal -u root -p -e "SHOW GLOBAL STATUS LIKE 'Threads_connected'; SHOW VARIABLES LIKE 'max_connections';"
Enter password:
+-------------------+-------+
| Variable_name     | Value |
+-------------------+-------+
| Threads_connected | 498   |
+-------------------+-------+
+-----------------+-------+
| Variable_name    | Value |
+-----------------+-------+
| max_connections  | 500   |
+-----------------+-------+

Sens : Vous êtes au bord du gouffre. Les nouvelles connexions seront refusées ; WordPress affichera l’erreur générique.

Décision : Atténuation immédiate : stoppez la tempête de connexions (cache, limitation, tuer clients abusifs, redémarrer PHP-FPM prudemment). Ensuite corrigez la cause : stratégie de connexions persistantes, performance des requêtes, nombre de processus PHP-FPM et pooling de connexions (si applicable).

Task 7: Identify top connection sources and what they’re doing

cr0x@server:~$ mysql -h db.internal -u root -p -e "SHOW FULL PROCESSLIST\G" | sed -n '1,80p'
Enter password:
*************************** 1. row ***************************
     Id: 91231
   User: wpuser
   Host: 10.10.3.21:51344
     db: wpdb
Command: Query
   Time: 24
  State: Sending data
   Info: SELECT option_name, option_value FROM wp_options WHERE autoload = 'yes'
*************************** 2. row ***************************
     Id: 91244
   User: wpuser
   Host: 10.10.3.21:51362
     db: wpdb
Command: Query
   Time: 29
  State: Copying to tmp table
   Info: SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts ...

Sens : Requêtes longues, tables temporaires et « Sending data » peuvent indiquer des index manquants, des ensembles de résultats énormes ou une lenteur du stockage.

Décision : Si vous voyez une requête coûteuse répétée, vous pouvez temporairement tuer les pires pour restaurer le service, puis ajouter des index ou corriger le plugin/thème qui les génère.

Task 8: Kill a runaway query (surgical, not angry)

cr0x@server:~$ mysql -h db.internal -u root -p -e "KILL 91244;"
Enter password:

Sens : Le thread est terminé. S’il réapparaît instantanément, quelque chose martèle la DB (cron, trafic, bot, plugin).

Décision : Si tuer aide temporairement, mettez en place des contrôles de trafic (règles WAF, caching, verrouillage admin) et chassez la source.

Task 9: Check PHP-FPM health and backlog (web tier can be the villain)

cr0x@server:~$ sudo systemctl status php8.2-fpm --no-pager
● php8.2-fpm.service - The PHP 8.2 FastCGI Process Manager
     Loaded: loaded (/lib/systemd/system/php8.2-fpm.service; enabled; preset: enabled)
     Active: active (running) since Thu 2025-12-26 01:55:02 UTC; 18min ago
   Main PID: 1887 (php-fpm8.2)
     Status: "Processes active: 52, idle: 1, Requests: 10432, slow: 219, Traffic: 0.6req/sec"

Sens : Si vous avez beaucoup de workers actifs, peu d’inactifs et des requêtes lentes en hausse, PHP est saturé. PHP saturé crée souvent plus de charge DB via des retries, timeouts et essaims de requêtes.

Décision : Si PHP-FPM est à fond, réduisez la concurrence ou ajoutez de la capacité. N’augmentez pas bêtement les limites ; vous transformerez un refus DB en effondrement serveur complet.

Task 10: Validate the DB_HOST socket vs TCP mismatch

cr0x@server:~$ sudo ls -l /var/run/mysqld/
total 4
srwxrwxrwx 1 mysql mysql 0 Dec 26 01:58 mysqld.sock
-rw-r--r-- 1 mysql mysql 5 Dec 26 01:58 mysqld.pid

cr0x@server:~$ php -r 'echo ini_get("mysqli.default_socket"), PHP_EOL;'
/var/run/mysqld/mysqld.sock

Sens : Le socket existe et PHP attend le même chemin. Si PHP attend un socket différent, les connexions locales peuvent échouer même si la DB tourne.

Décision : En cas de décalage, réglez DB_HOST sur 127.0.0.1 pour forcer le TCP (atténuation rapide) ou corrigez les paramètres de socket dans la config PHP (correction durable).

Task 11: Check disk space and inode exhaustion (the classic “DB died” impersonator)

cr0x@server:~$ df -h /var/lib/mysql
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda2       100G   99G  1.0G  99% /var

cr0x@server:~$ df -i /var/lib/mysql
Filesystem       Inodes  IUsed   IFree IUse% Mounted on
/dev/sda2       6553600 6553200    400  100% /var

Sens : Vous êtes à court d’inodes. MySQL peut « fonctionner » mais incapable de créer des tables temporaires, redo logs ou nouveaux fichiers. WordPress observe des échecs de connexion ou des timeouts.

Décision : Libérez immédiatement de l’espace/des inodes (logs, caches, anciennes sauvegardes), puis planifiez une vraie correction de partitionnement/stockage. L’épuisement d’inodes est un problème structurel, pas un caprice.

Task 12: Look for I/O stalls that turn DB into a liar (it says “running,” it’s actually stuck)

cr0x@server:~$ iostat -xz 1 3
Linux 6.1.0 (server)  12/26/2025  _x86_64_  (8 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
          10.21    0.00    5.02   42.11    0.00   42.66

Device            r/s     w/s   rkB/s   wkB/s  avgrq-sz avgqu-sz   await  r_await  w_await  svctm  %util
sda              8.00  120.00   256.0  6144.0     98.0     12.4   102.5    15.2   108.4   2.10   96.0

Sens : Forte %iowait et fort await avec utilisation proche de 100 % : votre disque est le goulot. Les requêtes MySQL vont se bloquer ; les clients vont timeouter ; WordPress signalera « can’t connect ».

Décision : Réduisez la pression d’écriture (arrêtez jobs bruyants, diminuez les pics de logs), migrez la DB vers un stockage plus rapide ou montez verticalement. Si c’est un disque VM partagé, vous pouvez être victime de voisins bruyants.

Task 13: Check for filesystem errors or read-only remount

cr0x@server:~$ mount | grep ' /var '
/dev/sda2 on /var type ext4 (ro,relatime,errors=remount-ro)

cr0x@server:~$ sudo dmesg | tail -n 20
[12345.678901] EXT4-fs error (device sda2): ext4_journal_check_start:83: Detected aborted journal
[12345.678905] EXT4-fs (sda2): Remounting filesystem read-only

Sens : Le système de fichiers a été remonté en lecture seule suite à des erreurs. MySQL peut rester démarré mais ne peut plus écrire, et tout s’écroule ensuite.

Décision : Traitez comme un incident de stockage. Arrêtez MySQL proprement si possible, planifiez un fsck et restaurez depuis des sauvegardes si nécessaire. N’appelez pas au secours en « bricolant » ; vous pouvez aggraver la corruption.

Task 14: Confirm WordPress is not pointing at the wrong database host after a migration

cr0x@server:~$ sudo -u www-data php -r "require '/var/www/html/wp-config.php'; echo DB_HOST, PHP_EOL;"
db.internal

cr0x@server:~$ ping -c 1 db.internal
PING db.internal (10.10.2.15) 56(84) bytes of data.
64 bytes from 10.10.2.15: icmp_seq=1 ttl=63 time=0.493 ms

Sens : La config WordPress se résout et l’hôte est joignable au niveau ICMP. (ICMP n’est pas la preuve d’un service TCP, mais c’est un contrôle de bon sens rapide.)

Décision : Si le ping fonctionne mais que MySQL ne répond pas, concentrez-vous sur le firewall et l’écoute DB. Si les deux échouent, vous avez un problème de routage ou de DNS.

Task 15: Validate user grants from the DB side (remote host mismatch is a classic)

cr0x@server:~$ mysql -u root -p -e "SHOW GRANTS FOR 'wpuser'@'10.10.3.%';"
Enter password:
+--------------------------------------------------------------------------------------------------+
| Grants for wpuser@10.10.3.%                                                                      |
+--------------------------------------------------------------------------------------------------+
| GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER ON `wpdb`.* TO `wpuser`@`10.10.3.%` |
+--------------------------------------------------------------------------------------------------+

Sens : L’utilisateur est autorisé depuis ce sous‑réseau. Si vous n’avez que 'wpuser'@'localhost', les connexions distantes échoueront avec « Access denied ».

Décision : Corrigez les grants pour refléter la réalité. Après des migrations, les hypothèses « localhost » sont des tueurs silencieux.

Task 16: Spot a table crash and do a safe-ish repair (MyISAM) or a safer check (InnoDB)

cr0x@server:~$ mysql -h db.internal -u root -p -e "CHECK TABLE wpdb.wp_options;"
Enter password:
+------------------+-------+----------+--------------------------------+
| Table            | Op    | Msg_type | Msg_text                       |
+------------------+-------+----------+--------------------------------+
| wpdb.wp_options  | check | status   | OK                             |
+------------------+-------+----------+--------------------------------+

Sens : La vérification basique d’intégrité indique OK. Si vous voyez « corrupt » sur des tables MyISAM, REPAIR TABLE peut aider. Pour InnoDB, la corruption est une histoire plus complexe.

Décision : Si une corruption apparaît et que vous êtes sur InnoDB : priorisez la restauration depuis sauvegardes ou utilisez prudemment les modes de récupération InnoDB. « Réparer » n’est pas une baguette magique pour InnoDB.

Erreurs fréquentes : symptôme → cause racine → correction

Cette section est volontairement spécifique. Les conseils génériques sont la façon dont les incidents deviennent des événements récurrents inscrits au calendrier.

1) Symptom: error appears after a DNS change or migration

  • Cause racine : DB_HOST pointe vers un ancien nom/IP, ou le TTL DNS + cache envoient encore certains serveurs vers l’ancienne DB.
  • Correction : Confirmez DB_HOST sur chaque nœud web ; videz les caches DNS locaux quand c’est possible ; maintenez un point d’accès DB stable (VIP/CNAME) et migrez derrière celui‑ci.

2) Symptom: intermittent errors under traffic spikes, fine at low traffic

  • Cause racine : MySQL atteint max_connections, PHP-FPM a trop de workers, ou vous avez un essaim de requêtes sur des pages non mises en cache.
  • Correction : Ajoutez du caching pour les parcours en lecture, limitez la concurrence PHP-FPM, augmentez la capacité DB et arrêtez de croire que l’on peut « scaler uniquement le web » si la DB est le goulot.

3) Symptom: DB service “running” but connections time out

  • Cause racine : stalls I/O, remontage en lecture seule du système de fichiers, ou InnoDB bloqué en récupération/pression de flush.
  • Correction : Mesurez la latence disque, vérifiez dmesg et les drapeaux de montage, réduisez la charge d’écriture et migrez la DB vers un stockage adapté si nécessaire.

4) Symptom: “Access denied for user” after changing the password

  • Cause racine : WordPress utilise d’anciens identifiants ; la gestion de configuration n’a pas propagé le changement ; ou les grants de l’utilisateur sont host‑spécifiques et l’identité de l’hôte a changé.
  • Correction : Mettez à jour wp-config.php de façon cohérente, vérifiez les grants pour l’hôte de connexion, et faites pivoter les secrets via un process contrôlé (pas un paste sur Slack).

5) Symptom: error appears only on some pages (admin works, public doesn’t)

  • Cause racine : cache/CDN qui sert des pages d’erreur obsolètes ; ou un plugin déclenche des requêtes lourdes seulement sur certaines routes.
  • Correction : Purgez les caches, contournez le CDN pour le diagnostic, puis profilez les requêtes lentes liées à ces routes.

6) Symptom: error appeared right after enabling a “performance” plugin

  • Cause racine : cache d’objets mal configuré (endpoint Redis erroné), comportement cron/heartbeat agressif, ou plugin qui inonde la DB de requêtes non mises en cache.
  • Correction : Désactivez le plugin pour restaurer le service, puis réintroduisez‑le avec des tests de charge mesurés. Travailler la performance sans mesure, c’est de l’artisanat.

7) Symptom: “MySQL server has gone away” and then WordPress shows connection error

  • Cause racine : max packet trop petit pour de grosses requêtes, timeouts de connexions inactives, redémarrage DB, ou interruptions réseau.
  • Correction : Vérifiez les logs DB pour des redémarrages, ajustez les timeouts et max_allowed_packet si nécessaire, et réglez la fiabilité réseau entre les couches.

Modes de défaillance du stockage et du système de fichiers qui se font passer pour un « DB down »

Voici la vérité impopulaire de l’ingénieur stockage : beaucoup d’incidents « connexion base de données » sont en réalité des incidents de stockage déguisés.

La latence disque est un problème de connectivité déguisé

Si InnoDB ne peut pas flush, il appliquera une rétro‑pression. Les requêtes font la queue. Les threads s’accumulent. Les connexions atteignent des timeouts. Du point de vue de WordPress, la DB pourrait tout aussi bien être débranchée.

Surveillez :

  • Forte pression fsync : les flushs de redo log se bloquent sur des disques lents.
  • Tempêtes de swap : la pression mémoire DB expulse des pages ; la latence explose.
  • Amplification d’écriture : tables temporaires sur disque, grands tris, états Copying to tmp table.

Épuisement d’inodes : la façon stupide de tomber

Les bases créent des fichiers, des tables temporaires, des binlogs et des redo logs. Si vous manquez d’inodes, l’OS refusera poliment. MySQL dégradera sans politesse. WordPress renverra simplement la même erreur générique, parce que bien sûr.

Remontage en lecture seule : la catastrophe silencieuse

Ext4 avec errors=remount-ro vous rend service : il évite d’aggraver la corruption. Mais il transforme chaque écriture en échec, et les bases de données sont essentiellement des écritures déguisées en lectures.

Stockage en réseau et « la DB est lente aujourd’hui »

Si votre base est sur un stockage réseau, une baie surchargée peut se traduire par des secondes de latence au niveau des blocs. MySQL attendra patiemment. Les clients, non. Si vous êtes cloudé sur des volumes partagés, vous pouvez aussi être throttlé. L’OS n’annonce généralement pas cela avec tambours ; il devient juste lent.

Prévention qui fonctionne vraiment (pas des impressions)

Prévenir n’est pas « ajouter plus de CPU ». Pour la fiabilité des bases WordPress, la prévention consiste à contrôler la concurrence, stabiliser la latence du stockage et rendre les défaillances visibles avant qu’elles ne deviennent un message sur la page d’accueil.

1) Placez la base sur un stockage qui se comporte sous pression

  • Utilisez un stockage SSD/NVMe pour le répertoire de données MySQL et les redo logs.
  • Privilégiez le NVMe local plutôt que des volumes réseau à « IOPS mystère » pour les sites à fort trafic.
  • Surveillez la latence disque (await, %util) comme vous surveillez le CPU.

2) Limitez la concurrence au niveau web

Si PHP-FPM se voit autorisé à engendrer une armée, il le fera. Puis chaque worker ouvre des connexions DB, et votre base devient le videur le plus triste du monde.

  • Définissez un pm.max_children raisonnable en fonction du CPU, de la mémoire et de la capacité DB.
  • Utilisez le caching pour le trafic anonyme. La plupart des pages WordPress n’ont pas besoin d’accéder à la DB à chaque requête.
  • Limitez les endpoints de connexion et XML‑RPC si vous n’en avez pas besoin.

3) Faites de la « connectivité DB » un SLO monitoré, pas une superstition

Surveillez :

  • Le temps de connexion TCP depuis les nœuds web vers la DB (checks synthétiques).
  • MySQL Threads_connected, Threads_running et les connexions avortées.
  • La latence disque et les compteurs d’erreurs du système de fichiers.
  • Les pics de volume du slow query log.

4) Sauvegardes qui restaurent, pas des sauvegardes qui existent

Une sauvegarde jamais restaurée est une histoire du soir. Exercez les restorations régulièrement, y compris :

  • Des dumps logiques pour la portabilité (mysqldump ou équivalent).
  • Des sauvegardes physiques pour la rapidité (snapshots cohérents au niveau fichier ou outils de sauvegarde).
  • La récupération point‑in‑time si vous avez des binlogs et un plan.

5) Évitez les points uniques de défaillance quand c’est important

Tout site WordPress n’a pas besoin de HA, mais si votre activité en dépend, construisez :

  • Primary/replica avec bascule automatisée testée soigneusement.
  • Séparation du web et du DB pour que la montée en charge d’un côté n’affecte pas l’autre.
  • Des vérifications santé qui détectent « la DB accepte des connexions et peut exécuter des requêtes », pas seulement « le port est ouvert ».

6) Gardez WordPress raisonnable : réduisez la charge de requêtes et les surprises

  • Auditez les plugins. Chaque plugin est un DBA potentiel que vous n’avez pas engagé.
  • Utilisez correctement le cache d’objets (et surveillez‑le).
  • Mettez à jour le cœur WordPress et PHP pour des améliorations de performance et de stabilité.

Blague #2 : Un plugin promettait « optimisation en un clic », ce qui est vrai — un clic suffit pour optimiser votre site en panne.

Listes de contrôle / plan étape par étape

During the incident: 15-minute stabilization checklist

  1. Confirmer l’impact : Est‑ce toutes les pages ou un sous‑ensemble ? L’erreur est‑elle servie par le CDN ?
  2. Vérifier la santé DB : statut du service, écoute, logs.
  3. Tester depuis l’hôte web : se connecter avec mysql en utilisant les identifiants WordPress.
  4. Vérifier la saturation : connexions, threads en cours, requêtes lentes.
  5. Vérifier le stockage : disque plein, inodes pleins, I/O wait, remontage en lecture seule.
  6. Atténuer : réduire la concurrence (temporairement), tuer les requêtes runaway, désactiver le plugin fautif si nécessaire.
  7. Communiquer : établir un rythme de mises à jour clair avec ce que vous savez et ce que vous faites ensuite.

Après stabilisation : checklist d’analyse racine (même jour)

  1. Extraire les fenêtres d’erreur des logs MySQL, PHP-FPM et du serveur web.
  2. Corréler avec les métriques : connexions, latence disque, CPU, mémoire, erreurs réseau.
  3. Identifier le déclencheur : pic de trafic, déploiement, changement de plugin, événement de stockage, changement DNS.
  4. Documenter le mode de défaillance exact (par ex. max_connections atteint, épuisement d’inodes, remontage en lecture seule).
  5. Implémenter un correctif préventif avec un plan de rollback.
  6. Ajouter/ajuster des moniteurs pour que cela déclenche une alerte plus tôt la prochaine fois (ou n’arrive plus).

Checklist de durcissement (hebdomadaire/mensuel)

  1. Tester la restauration des sauvegardes.
  2. Revoir la liste de plugins et supprimer le poids mort.
  3. Revoir les requêtes lentes et les opportunités d’indexation.
  4. Vérifier les tendances de croissance disque et d’utilisation des inodes.
  5. Patch OS, DB, PHP via un process contrôlé.
  6. Revoir la capacité : workers PHP-FPM vs max_connections DB vs hardware.

Trois mini-récits d’entreprise venus du terrain

Mini-récit 1 : L’incident causé par une mauvaise hypothèse

L’entreprise avait une architecture « simple » : quelques nœuds web et un service de base géré. L’équipe a migré WordPress vers de nouveaux serveurs web pour obtenir une version PHP plus récente et un meilleur CPU. Tout semblait correct en staging. Le basculement en production était prévu pour un matin calme.

Le basculement a eu lieu, le DNS a basculé et le trafic est arrivé. En quelques minutes : Error establishing a database connection. Les métriques DB semblaient normales. La DB était « up ». Les nœuds web étaient sains. Naturellement, tout le monde regardait WordPress comme s’il les avait trahis personnellement.

La mauvaise hypothèse était logée dans une seule ligne : DB_HOST était défini sur localhost sur les anciens serveurs, parce que la DB se trouvait autrefois sur la même machine. Lors de migrations précédentes, quelqu’un avait « temporairement » utilisé un tunnel SSH et n’avait jamais nettoyé la configuration. Sur les nouveaux serveurs, il n’y avait pas de MySQL local. WordPress essayait de se connecter à lui‑même. Échec prévisible.

La correction fut triviale : pointer DB_HOST vers le endpoint DB géré, déployer, terminé. La leçon durable n’était pas « mettre à jour DB_HOST ». C’était : ne laissez pas la dérive d’infrastructure vivre dans les configs applicatives sans tests qui valident la topologie. L’équipe a ajouté un contrôle pré‑déploiement pour valider la connectivité DB depuis chaque nœud web avant tout flip DNS.

Mini-récit 2 : L’optimisation qui s’est retournée contre eux

Une autre organisation avait un mandat de performance. Les pages étaient lentes, et quelqu’un a proposé : « Augmentons les workers PHP-FPM pour que les requêtes ne fassent pas la queue. » Cela semblait raisonnable. Les serveurs web avaient du CPU libre. Le changement a été déployé en heures ouvrables parce que le risque « semblait faible ».

Le résultat fut immédiat : WordPress a commencé à produire des erreurs de connexion à la base de données de manière intermittente. Pas une panne totale — juste assez pour ruiner les conversions et hanter le support client. MySQL atteignait les limites de connexions, et la latence des requêtes a explosé. La DB n’était pas dimensionnée pour la nouvelle concurrence. Plus de workers PHP signifiait plus de connexions DB simultanées, plus de cache misses et plus de pression sur les flushs InnoDB.

L’équipe a essayé la réaction instinctive : augmenter max_connections. Cela a acheté quelques minutes, puis le serveur a manqué de mémoire et a commencé à swapper. Désormais tout était lent : la DB, les nœuds web, même les connexions SSH. Ce n’était plus « un problème WordPress ». C’était une cascade d’épuisement des ressources.

Le rollback a corrigé la situation. La solution durable fut ennuyeuse : ajouter du caching pour le trafic anonyme, définir des limites PHP-FPM raisonnables, ajouter des index pour les pires requêtes, et scaler le stockage/IOPS de la DB. La plus grande « optimisation » fut simplement de ne pas générer du travail inutile.

Mini-récit 3 : La pratique ennuyeuse mais correcte qui a sauvé la mise

Une entreprise média exécutait WordPress comme partie d’une plateforme plus large. La DB était une primaire unique avec une réplique chaude. Rien d’extraordinaire. La discipline l’était : tests de restauration routiniers et un runbook de bascule documenté qui vivait dans le même repo que le code infra.

Un après‑midi, l’hôte primaire a eu des erreurs de système de fichiers après une mise à jour du kernel et un reboot. Il est revenu, mais le volume de données a été remonté en lecture seule. MySQL a démarré, puis a progressivement échoué en tentant d’écrire. WordPress a affiché l’erreur de connexion. Ils ont eu environ cinq minutes de confusion, puis le on‑call a reconnu le schéma : « en cours d’exécution, mais incapable d’écrire. »

Ils n’ont pas tenté d’héroïsme sur un système de fichiers endommagé. Ils ont exécuté le runbook : promouvoir la réplique, mettre à jour le endpoint DB, et redémarrer les nœuds web pour purger les connexions obsolètes. Le trafic a rapidement repris. Plus tard, ils ont réparé le primaire hors‑ligne et l’ont re‑peuplé correctement.

La pratique salvatrice n’était pas une automatisation magique. C’était une compétence ennuyeuse répétée : sauvegardes validées, étapes de bascule connues, et une culture d’équipe qui ne traite pas les systèmes de fichiers comme immortels.

Faits et contexte intéressants (brefs et concrets)

  • Fait 1 : WordPress a démarré en 2003, et la dépendance à MySQL existe depuis le début ; l’erreur « DB connection » hante les admins depuis deux décennies.
  • Fait 2 : Pendant des années, le driver DB par défaut de WordPress était l’ancienne extension mysql ; les installations modernes utilisent mysqli, ce qui modifie le comportement des sockets et des timeouts.
  • Fait 3 : Le comportement « Too many connections » de MySQL est notoirement abrupt : une fois le plafond atteint, les nouvelles sessions échouent immédiatement, même si le serveur est par ailleurs sain.
  • Fait 4 : InnoDB est devenu le moteur par défaut dans MySQL 5.5 ; auparavant, MyISAM était courant et les réparations de tables étaient plus fréquentes.
  • Fait 5 : Les TTL DNS peuvent maintenir d’anciens endpoints DB dans les caches clients bien plus longtemps que prévu, en particulier à travers des résolveurs conteneurisés et des démons de cache locaux.
  • Fait 6 : La confusion socket Unix vs TCP est plus ancienne que WordPress : les clients peuvent utiliser par défaut les sockets pour « localhost » mais le TCP pour « 127.0.0.1 », ce qui change les chemins d’auth et permissions.
  • Fait 7 : Beaucoup de plugins WordPress implémentent mal leurs propres couches de cache ; un cache d’objets mal configuré peut augmenter la charge DB au lieu de la réduire.
  • Fait 8 : Le temps de récupération après crash InnoDB est proportionnel à la taille des redo logs et à la charge ; après un crash, « la DB est up » peut encore signifier « la DB est occupée à se réparer ».
  • Fait 9 : Les systèmes de fichiers qui se remontent en lecture seule sur erreur sont une fonctionnalité de sécurité, pas un bug — les bases de données les détestent intensément.

FAQ

1) Why does WordPress show the same error for different failures?

Parce que l’échec survient au moment de la connexion, avant que WordPress puisse charger les options ou exécuter des requêtes signifiantes. Il ne peut pas distinguer « mauvais mot de passe » d’« hôte DB en feu » sans divulguer des détails. Vous avez besoin de vérifications côté plateforme.

2) Should I restart MySQL immediately?

Seulement si vous avez d’abord vérifié les logs et les symptômes de stockage. Redémarrer peut aider si le démon est bloqué, mais cela peut aussi empirer la récupération après crash ou masquer le vrai problème. Si vous voyez des erreurs disque ou des remontages en lecture seule, redémarrer est du cargo cult.

3) How do I know if it’s credentials vs connectivity?

Exécutez mysql -h ... -u ... -p -e "SELECT 1;" depuis le serveur web en utilisant les identifiants de wp-config.php. « Access denied » signifie auth/grants. « Can’t connect » signifie réseau/écoute/firewall. Les timeouts signifient souvent saturation ou stalls I/O.

4) Why does it happen only during traffic spikes?

Parce que la concurrence multiplie tout. Plus de requêtes → plus de workers PHP → plus de connexions DB → plus de contention de verrous et de pression de flush. Si vous êtes près de la capacité, un pic vous bascule en refus de connexions et timeouts.

5) Is increasing max_connections a good fix?

Parfois c’est un pansement à court terme. À long terme, cela peut se retourner contre vous en augmentant l’utilisation mémoire et le context switching. Corrigez le côté demande (caching, optimisation des requêtes, rate limiting) et le côté offre (ressources DB) ensemble.

6) Can a full disk cause a database connection error?

Oui. Disque plein ou inodes pleins peuvent empêcher MySQL de créer des tables temporaires ou d’écrire des logs, entraînant des stalls et des échecs qui se manifestent comme des problèmes de connexion au niveau applicatif.

7) What’s the fastest safe mitigation if the DB is overloaded?

Réduisez la charge d’abord : activez/vérifiez le full-page caching pour le trafic anonyme, limitez les endpoints abusifs et cappez les workers PHP-FPM. Tuer les pires requêtes peut acheter du temps, mais ce n’est pas une stratégie en soi.

8) How do I prevent plugin-caused DB meltdowns?

Traitez les changements de plugins comme des déploiements : rollout échelonné, comparaison de métriques, et plan de rollback. Auditez aussi les plugins trimestriellement. Moins de code, moins de chaos.

9) Why does switching DB_HOST from localhost to 127.0.0.1 sometimes “fix” it?

Parce que cela force le TCP au lieu d’un socket Unix. Si le chemin de socket est incorrect ou que les permissions sont bizarres, le TCP contourne le problème. C’est une atténuation valide ; la vraie correction est une configuration de socket cohérente.

10) If the database is remote, what’s the top hidden culprit?

La fiabilité du chemin réseau et la résolution de noms. Un petit changement DNS, une règle de firewall ou un problème de routage peut ressembler exactement à une panne DB du point de vue de WordPress.

Conclusion : prochaines étapes à faire aujourd’hui

Cette erreur WordPress est un symptôme, pas une cause. Traitez‑la comme une panne de production : isolez rapidement le domaine de défaillance, appliquez des atténuations chirurgicales, puis corrigez les problèmes sous‑jacents de capacité/configuration/stockage pour éviter la récidive.

  1. Rédigez votre runbook de diagnostic rapide en utilisant les tâches ci‑dessus, adapté à votre environnement (DB locale vs DB gérée, socket vs TCP).
  2. Ajoutez deux moniteurs aujourd’hui : une requête synthétique web→DB, et la latence disque sur l’hôte/volume DB.
  3. Limitez la concurrence (PHP-FPM et serveur web) en fonction de la capacité DB, pas de l’optimisme.
  4. Testez la restauration des sauvegardes cette semaine. Pas « vérifiez qu’elles existent ». Restaurez‑les.
  5. Auditez les plugins et supprimez tout ce qui n’est plus maintenu, redondant ou « installé temporairement » depuis 2019.
← Précédent
Blender et rendu GPU : comment les créateurs ont obtenu un nouveau super-pouvoir
Suivant →
ZFS recordsize : le réglage qui décide de 80 % des performances des fichiers

Laisser un commentaire