# Erreur 504 Gateway Timeout sur WordPress : solutions

> Erreur 504 Gateway Timeout sur WordPress : trouvez le script lent, réglez fastcgi_read_timeout, ProxyTimeout et PHP-FPM, ou découpez la tâche.

- Auteur : WordPress Développement
- Publié le : 2026-10-02
- Mis à jour le : 2026-10-02
- URL : https://www.wpmoderne.fr/erreurs-wordpress/erreur-504/

> Le serveur frontal (nginx, Apache, CDN) a attendu PHP trop longtemps et a abandonné. Identifiez le script lent dans le journal, puis allongez les délais du proxy et de PHP, ou découpez la tâche en lots.

Après de longues secondes d’attente, le navigateur affiche « 504 Gateway Timeout » (« 504 Gateway Time-out » avec nginx). La page ne s’est pas chargée, mais ce n’est pas forcément un plantage : **le serveur a continué de travailler** pendant que son intermédiaire, lui, a cessé d’attendre. L’erreur apparaît le plus souvent sur une action longue : import, sauvegarde, génération de rapport, enregistrement d’une très grosse page, appel d’API externe.

## Ce que signifie cette erreur

Une réponse 504 est émise par un *passerelle ou proxy* qui transmet votre requête à un serveur en amont et n’obtient pas de réponse dans le délai qui lui est imparti. WordPress est ici le serveur en amont : il n’a pas encore répondu, donc il ne peut pas avoir produit l’erreur lui-même (le libellé « Gateway Timeout » existe pourtant dans `get_status_header_desc()`, `wp-includes/functions.php`, comme dans la classe `WP_Http` pour les requêtes sortantes). Plusieurs maillons peuvent déclarer forfait :

- **nginx** devant PHP-FPM : la directive `fastcgi_read_timeout` vaut 60 secondes par défaut, et le journal indique « upstream timed out (110: Connection timed out) while reading response header from upstream » ;
- **Apache** avec `mod_proxy_fcgi` ou en proxy inverse : ce sont `ProxyTimeout` et `Timeout` qui comptent ;
- **Un CDN ou un répartiteur de charge** : le délai est fixé chez eux, souvent plus court que le vôtre, et vos réglages serveur n’y changent rien ;
- **PHP lui-même** : si `max_execution_time` ou `request_terminate_timeout` tranche avant le proxy, c’est une autre erreur qui s’affiche (voir la fiche [temps d’exécution dépassé](https://www.wpmoderne.fr/erreurs-wordpress/temps-execution-depasse/)).

Un 504 se distingue du [502](https://www.wpmoderne.fr/erreurs-wordpress/erreur-502/) (la réponse du serveur en amont est invalide ou la connexion est refusée) et du 503 (service indisponible ou saturé) : ici, la connexion est établie, mais la réponse n’arrive pas à temps.

## Diagnostic rapide

| Symptôme / constat | Cause probable | À vérifier |
| --- | --- | --- |
| Échec après une durée constante (60 s, 100 s…) | Délai d’un proxy ou d’un CDN atteint | Chronométrer l’échec avec `curl -w` ; réglages nginx, Apache, CDN |
| Uniquement sur un import, une sauvegarde, un export | Tâche longue exécutée dans la requête web | Découper en lots ou exécuter avec WP-CLI |
| Toutes les pages lentes puis 504 | Serveur saturé ou requête SQL lente | Journal des requêtes lentes PHP et MySQL ; charge du serveur |
| Échec uniquement quand une extension précise est active | Appel à une API externe qui ne répond pas | Journal PHP, test de la requête sortante (fiche cURL 28) |
| 504 avec la mention d’un CDN ou d’un WAF | Le CDN n’a pas reçu de réponse de l’origine | Accéder directement à l’origine, journal de l’origine |
| Le script va au bout malgré le 504 | Le travail continue après la coupure du proxy | Résultat en base de données ; journal PHP-FPM |

## Les causes les plus fréquentes

1. **Une tâche trop longue** exécutée dans une requête web : import de milliers de lignes, régénération de miniatures, sauvegarde.
2. **Un délai de proxy trop court** par rapport au travail demandé (60 secondes par défaut sur nginx).
3. **Une requête externe qui ne répond pas** : API de paiement, service d’e-mailing, serveur de licences, vérification de mises à jour.
4. **Une base de données lente ou verrouillée** : requêtes sans index, tables énormes, options chargées automatiquement trop nombreuses.
5. **Un serveur sous-dimensionné ou saturé** : les requêtes attendent un processus PHP libre.
6. **Un CDN ou un WAF** dont le délai est plus court que celui de votre serveur.

## Solutions pas à pas

Sauvegardez fichiers et base avant de toucher à la configuration, et testez-la avant de recharger un service (`nginx -t` ou `apachectl configtest`). Du moins invasif au plus technique :

### 1. Mesurer le délai et trouver le maillon

Un délai constant trahit un proxy : mesurez le temps écoulé jusqu’à l’échec.

```
curl -s -o /dev/null -w '%{http_code} en %{time_total} s\n' https://www.exemple.fr/wp-admin/admin-ajax.php?action=mon_action
```

Si l’échec survient toujours à la même seconde (60, 100, 120…), cherchez le réglage correspondant. Puis lisez le journal d’erreurs du serveur web à l’heure du test :

```
sudo tail -n 50 /var/log/nginx/error.log
sudo tail -n 50 /var/log/apache2/error.log
```

Pour croiser ces journaux avec ceux de PHP et de WordPress, l’article [centraliser les logs nginx, PHP et WordPress](https://www.wpmoderne.fr/hebergement/centraliser-logs-nginx-php-wordpress-diagnostiquer/) détaille une méthode.

### 2. Alléger la tâche plutôt que d’allonger le délai

Allonger les délais masque le problème : une page qui met plus d’une minute à répondre bloque un processus PHP pendant tout ce temps. Quand c’est possible, traitez par lots (quelques dizaines d’éléments par appel, avec reprise), ou lancez la tâche en ligne de commande, qui n’a aucun proxy devant elle :

```
wp cron event run --due-now
wp media regenerate --yes
wp import export.xml --authors=skip
```

(`wp import` demande l’extension WordPress Importer.) La méthode de découpage est détaillée dans [traiter 50 000 éléments sans timeout](https://www.wpmoderne.fr/extensions/traiter-50000-elements-sans-timeout-lots-reprise/), et le cas d’un proxy amont trop court dans [504 Gateway Timeout sur un import volumineux](https://www.wpmoderne.fr/hebergement/504-gateway-timeout-import-volumineux-proxy-amont/).

### 3. Allonger les délais de nginx

Limitez l’allongement à la zone concernée plutôt qu’à tout le site :

```
# bloc server : uniquement l'administration
location ^~ /wp-admin/ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/run/php/php8.2-fpm.sock;
    fastcgi_read_timeout 300s;
    fastcgi_send_timeout 300s;
}
```

Adaptez le nom de l’include et le socket à votre installation, puis `sudo nginx -t && sudo systemctl reload nginx`. Si nginx est lui-même derrière un autre proxy, réglez aussi `proxy_read_timeout` sur celui-ci.

### 4. Allonger les délais d’Apache

```
# dans le VirtualHost
ProxyTimeout 300
Timeout 300
```

`ProxyTimeout` s’applique aux échanges avec PHP-FPM via `mod_proxy_fcgi` ; `Timeout` (300 par défaut sous Debian) borne les entrées-sorties de la connexion. Rechargez avec `sudo systemctl reload apache2`.

### 5. Aligner PHP sur le proxy

Un délai de proxy plus long ne sert à rien si PHP coupe avant. Alignez la limite de PHP et celle du pool PHP-FPM :

```
; php.ini ou .user.ini
max_execution_time = 300

; pool PHP-FPM (ex. /etc/php/8.2/fpm/pool.d/monsite.conf)
request_terminate_timeout = 300s
```

Sur un mutualisé, ces valeurs se règlent dans le panneau (rubrique PHP) ou via `.user.ini` à la racine du site. Rechargez PHP-FPM : `sudo systemctl reload php8.2-fpm`.

### 6. Trouver le script ou la requête lente

Dans le pool PHP-FPM, activez le journal des requêtes lentes : il écrit la pile d’appels des scripts qui dépassent le seuil.

```
request_slowlog_timeout = 10s
slowlog = /var/log/php8.2-fpm-slow.log
```

Côté base de données, activez le journal des requêtes lentes de MySQL ou MariaDB (`slow_query_log` et `long_query_time`), ou installez temporairement l’extension Query Monitor pour voir quelle requête, quel crochet ou quel appel HTTP prend le temps.

### 7. Si un CDN ou un WAF est devant

Testez en contournant le CDN (accès direct à l’IP d’origine avec un en-tête `Host`, ou en désactivant temporairement le proxy). Si l’erreur disparaît, le délai du CDN est en cause : il est souvent fixe selon l’offre (de l’ordre de 100 secondes chez certains), donc la seule vraie solution est de rendre la tâche plus courte ou de la lancer hors requête web.

## Prévenir l’erreur

- Ne lancez jamais une tâche de plusieurs minutes dans une requête web : planifiez-la avec un cron système ou découpez-la en lots avec reprise.
- Donnez un **délai explicite** aux appels sortants (`wp_remote_get()` avec `timeout`) pour qu’une API externe lente ne bloque pas la page.
- Gardez le journal des requêtes lentes de PHP-FPM actif : il signale la dérive avant l’incident.
- Surveillez la taille de la table des options et des tables volumineuses, et ajoutez les index manquants.
- Documentez les délais de chaque maillon (CDN, proxy, PHP) pour savoir lequel ajuster.
