PHP-FPM-Pools für WordPress richtig dimensionieren: pm.max_children messen und einstellen
So stellen Sie den PHP-FPM-Pool Ihrer WordPress-Website anhand gemessener Werte ein: Speicherbedarf je Prozess ermitteln, pm.max_children berechnen, Betriebsart wählen, Statusseite und Slowlog nutzen.
Mit KI erstellt – redaktionelle Prüfung ausstehend
WerbelinksMit * markierte Links sind Werbelinks: Bei einem Kauf erhalten wir eine Provision, der Preis bleibt gleich. Mehr dazu

Wenn eine WordPress-Website auf dem eigenen Server mit nginx oder Apache und PHP-FPM läuft, entscheidet ein kleiner Konfigurationsblock darüber, wie viele Besucher gleichzeitig bedient werden: der PHP-FPM-Pool. Ist er zu knapp, warten Besucher in der Schlange, und im Log erscheint „server reached pm.max_children setting“. Ist er zu großzügig, reicht der Arbeitsspeicher nicht mehr, und der Server beginnt auszulagern oder beendet Prozesse. Diese Anleitung zeigt, wie Sie den Pool anhand echter Messwerte statt nach Forenwerten einstellen, welche Betriebsart zu Ihrer Website passt und wie Sie Engpässe später erkennen.
Voraussetzungen
- WordPress 7.1 auf einem eigenen Server oder VPS mit Root- oder sudo-Zugriff per SSH. Bei einfachem Webhosting legt der Hoster die Grenzen fest, dann hilft Ihnen die Anleitung Hosting-Ressourcen, PHP-Worker und Memory-Limit prüfen.
- PHP-FPM ist installiert und mit dem Webserver verbunden. Die Beispiele verwenden Debian 13 mit PHP 8.4 und nginx. Wie Sie das einrichten, steht in WordPress auf nginx mit PHP-FPM konfigurieren. Unter Ubuntu oder mit anderer PHP-Version ändern sich Pfade und Dienstname entsprechend.
- Ein aktuelles Backup der Website und eine Kopie der Pool-Datei, bevor Sie etwas ändern. Ein Tippfehler in der Pool-Datei kann PHP-FPM beim Neuladen komplett stoppen.
- Rund 30 Minuten Zeit und idealerweise ein Zeitfenster mit wenig Besuchern.
Schritt 1: Aktuelle Pool-Einstellungen ablesen
Jeder Pool ist ein eigener Abschnitt in einer Datei unter /etc/php/8.4/fpm/pool.d/. Auf Debian heißt der Standard-Pool www. Sichern Sie die Datei und lesen Sie die aktiven Zeilen ohne Kommentare aus:
sudo cp /etc/php/8.4/fpm/pool.d/www.conf /root/www.conf.bak
grep -vE '^\s*(;|$)' /etc/php/8.4/fpm/pool.d/www.conf
Auf einem frisch installierten Debian 13 sah das im Test so aus:
[www]
user = www-data
group = www-data
listen = /run/php/php8.4-fpm.sock
listen.owner = www-data
listen.group = www-data
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
Die entscheidende Zeile ist pm.max_children. Laut PHP-Handbuch legt sie fest, wie viele Anfragen gleichzeitig bearbeitet werden. Jede weitere Anfrage wartet, bis ein Prozess frei wird. Fünf Prozesse sind ein vorsichtiger Standard, für Shops oft zu wenig, für 1 GB Arbeitsspeicher eventuell schon zu viel.
Verifizieren: Sie kennen den Namen Ihres Pools, den Socket und die aktuellen Werte für pm und pm.max_children, und eine Sicherungskopie der Datei liegt unter /root/www.conf.bak.
Schritt 2: Statusseite und Slowlog einschalten
Bevor Sie Werte ändern, brauchen Sie Messpunkte. PHP-FPM bringt dafür eine Statusseite und ein Protokoll für langsame Anfragen mit. Ergänzen Sie im Pool:
pm.status_path = /fpm-status
ping.path = /fpm-ping
request_slowlog_timeout = 5s
slowlog = /var/log/php8.4-fpm-www-slow.log
Die Statusseite darf nicht öffentlich erreichbar sein, sie verrät laufende Skripte und Adressen. Geben Sie sie in nginx nur für den Server selbst frei. Setzen Sie den Block vor den allgemeinen PHP-Block, damit er zuerst greift:
location ~ ^/(fpm-status|fpm-ping)$ {
allow 127.0.0.1;
deny all;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $fastcgi_script_name;
fastcgi_pass unix:/run/php/php8.4-fpm.sock;
}
Testen Sie beide Konfigurationen und laden Sie die Dienste neu:
sudo php-fpm8.4 -t && sudo systemctl reload php8.4-fpm
sudo nginx -t && sudo systemctl reload nginx
curl -s http://127.0.0.1/fpm-status
Die Ausgabe enthält unter anderem diese Zeilen:
pool: www
process manager: dynamic
listen queue: 0
max listen queue: 0
idle processes: 0
active processes: 1
total processes: 1
max active processes: 1
max children reached: 0
slow requests: 0
Wichtig sind drei Werte. max children reached ist laut PHP-Handbuch 1 oder größer, sobald der Pool einmal an seine Grenze gestoßen ist. max listen queue zeigt, wie viele Anfragen höchstens gleichzeitig auf einen freien Prozess gewartet haben. slow requests zählt Anfragen, die länger als request_slowlog_timeout liefen.
Verifizieren: curl -s http://127.0.0.1/fpm-ping antwortet auf dem Server mit pong, ein Aufruf derselben Adresse von außen liefert 403.
Schritt 3: Speicherbedarf je Prozess messen
Die Grenze für pm.max_children ergibt sich aus dem Arbeitsspeicher, nicht aus einer Faustregel. Lassen Sie die Website einige Zeit normal laufen und messen Sie dann den belegten Speicher der Pool-Prozesse:
ps -o pid,rss,cmd -C php-fpm8.4
ps --no-headers -o rss -C php-fpm8.4 | awk '{s+=$1; n++} END {printf "%d Prozesse, Schnitt %.0f MB\n", n, s/n/1024}'
Im Test mit einer frischen WordPress-Installation ohne Plugins belegten die Pool-Prozesse nach einigen Aufrufen jeweils 46 bis 53 MB, der Master-Prozess etwa 11 MB. Rechnen Sie für den Durchschnitt nur mit den Zeilen pool www, der Master-Prozess senkt sonst den Schnitt. Websites mit Page-Builder oder WooCommerce liegen deutlich höher.
Der Wert RSS enthält auch Speicher, den sich Prozesse teilen, etwa den OPcache. Für eine Obergrenze ist das die sichere Seite. Beachten Sie außerdem das memory_limit aus der php.ini (im Test 128M): Einzelne Anfragen, etwa ein Import oder eine Bildbearbeitung, dürfen bis zu dieser Grenze wachsen. Mehr dazu in Speicherlimit in WordPress erhöhen.
Verifizieren: Sie haben einen Durchschnittswert in MB je Pool-Prozess, gemessen nach typischen Seitenaufrufen und nicht direkt nach dem Neustart.
Schritt 4: pm.max_children berechnen und die Betriebsart wählen
Ermitteln Sie mit free -m, wie viel Arbeitsspeicher insgesamt vorhanden ist. Ziehen Sie ab, was Datenbank, Webserver, Betriebssystem und andere Dienste brauchen. Den Rest teilen Sie durch Ihren Messwert:
pm.max_children = Speicher für PHP in MB / MB je Prozess
Beispiel: 4096 MB gesamt, davon 1536 MB für MariaDB, nginx und System
2560 MB / 60 MB = 42, gewählt: 40
Runden Sie ab und lassen Sie Luft für Ausreißer. Mehr Prozesse helfen außerdem nur, solange genügend CPU-Kerne da sind. Rechnen alle Prozesse gleichzeitig, teilen sie sich die Kerne, und jede Anfrage wird langsamer.
Die Betriebsart legt fest, wie PHP-FPM die Prozesse verwaltet:
| pm | Verhalten | Passt für |
|---|---|---|
| static | immer genau pm.max_children Prozesse | Server nur für diese Website, gleichmäßig hohe Last |
| dynamic | Anzahl schwankt zwischen den Spare-Werten und pm.max_children | die meisten Unternehmenswebsites |
| ondemand | Prozesse erst bei Anfrage, Ende nach pm.process_idle_timeout | kleine Server, mehrere Pools, wenig Besucher |
Für dynamic ein Beispiel für einen Server mit 4 GB:
pm = dynamic
pm.max_children = 40
pm.start_servers = 6
pm.min_spare_servers = 4
pm.max_spare_servers = 8
pm.max_requests = 500
pm.max_requests startet einen Prozess nach der angegebenen Zahl von Anfragen neu. Das PHP-Handbuch nennt das als Mittel gegen Speicherlecks in Bibliotheken, Standard ist 0 (nie).
Bei ondemand lief im Test die erste Anfrage nach einer Pause spürbar langsamer (0,52 statt 0,08 Sekunden), weil PHP-FPM erst einen Prozess starten musste. Nach der Leerlaufzeit von 10 Sekunden war der Prozess wieder beendet.
Verifizieren: sudo php-fpm8.4 -t meldet „test is successful“. Die Summe aus pm.max_children mal Messwert passt in den freien Arbeitsspeicher.
Schritt 5: Zeitgrenzen abstimmen und neu laden
Hängt eine Anfrage, etwa weil ein Plugin auf eine externe Schnittstelle wartet, blockiert sie einen Prozess. request_terminate_timeout beendet solche Prozesse nach der angegebenen Zeit. Laut PHP-Handbuch ist die Einstellung für Fälle gedacht, in denen max_execution_time das Skript nicht stoppt, denn Wartezeiten auf Netzwerk oder Datenbank zählen dort je nach System nicht mit. Setzen Sie den Wert höher als die längste legitime Aufgabe, etwa Backups oder Importe:
request_terminate_timeout = 120s
request_slowlog_timeout = 5s
Der Slowlog-Wert muss kleiner sein als die Abbruchzeit, sonst startet PHP-FPM nicht. Denken Sie auch an nginx: fastcgi_read_timeout steht laut nginx-Dokumentation standardmäßig auf 60 Sekunden. Läuft PHP länger, bricht nginx vorher ab und liefert 504, obwohl PHP noch arbeitet.
Laden Sie den Dienst nur neu, wenn der Test erfolgreich war. Die Verknüpfung mit && sorgt dafür:
sudo php-fpm8.4 -t && sudo systemctl reload php8.4-fpm
Im Test wurde der Pool einmal ohne diese Prüfung neu geladen, mit einem Slowlog-Wert über der Abbruchzeit. PHP-FPM beendete sich vollständig, und jede Seite lieferte sofort 502. Ein Reload mit fehlerhafter Datei lässt den alten Stand also nicht einfach weiterlaufen.
Verifizieren: systemctl status php8.4-fpm zeigt „active (running)“, die Startseite liefert 200, und die Statusseite zeigt den neuen Wert unter process manager.
Schritt 6: Unter Last prüfen und beobachten
Ob die Werte passen, sehen Sie erst unter Last. Im Test lief ein Pool mit pm.max_children = 2 gegen sechs gleichzeitige Aufrufe eines Skripts, das 4 Sekunden rechnet. Die Antworten kamen paarweise nach etwa 4, 8 und 12 Sekunden, der letzte Besucher wartete also dreimal so lange wie der erste. Im Protokoll /var/log/php8.4-fpm.log stand:
WARNING: [pool www] server reached pm.max_children setting (2), consider raising it
Auf der Statusseite sprang max children reached auf 1. Genau diese beiden Stellen sollten Sie nach der Umstellung einige Tage beobachten:
grep -c 'reached pm.max_children' /var/log/php8.4-fpm.log
curl -s http://127.0.0.1/fpm-status | grep -E 'max children|max listen|slow'
Erscheint die Warnung regelmäßig, prüfen Sie zuerst im Slowlog, welche Skripte lange laufen. Oft ist ein einzelnes Plugin die Ursache, mehr Prozesse verschieben das Problem nur. Die Anleitung Langsame Plugins mit Query Monitor finden hilft bei der Suche. Erst wenn die Anfragen selbst schnell sind und der Speicher reicht, erhöhen Sie pm.max_children schrittweise.
Solche Grenzwerte sind keine einmalige Einstellung. Neue Plugins, ein Theme-Wechsel oder eine neue PHP-Version verändern den Speicherbedarf, und Updates wollen regelmäßig eingespielt werden. Wer diese Pflege nicht selbst im Kalender halten möchte, kann sie abgeben: Die WordPress-Wartung von wordpressupdate.de übernimmt Updates von WordPress, Plugins und Themes mit Kompatibilitätsprüfung, wöchentliche Backups auf externen Speicher und die Firewall.
Verifizieren: Nach einigen Tagen Betrieb steht max children reached auf 0 oder steigt nur selten, und free -m zeigt auch zu Spitzenzeiten noch verfügbaren Arbeitsspeicher.
Typische Fehler
PHP-FPM startet nach der Änderung nicht mehr. Der Konfigurationstest nennt die Ursache genau. Diese Meldungen traten im Test auf:
ALERT: [pool www] pm.max_children must be a positive value
ALERT: [pool www] pm.max_spare_servers(2) must not be less than pm.min_spare_servers(3)
ERROR: [pool www] 'request_slowlog_timeout' (3) can't be greater than 'request_terminate_timeout' (2)
ERROR: FPM initialization failed
Korrigieren Sie den genannten Wert oder spielen Sie die Sicherung aus Schritt 1 zurück. Bei dynamic muss pm.start_servers zwischen den beiden Spare-Werten liegen.
502 Bad Gateway bei langen Aufgaben. Beendet request_terminate_timeout einen Prozess, schreibt PHP-FPM „execution timed out (2.320891 sec), terminating“, und nginx meldet „recv() failed (104: Connection reset by peer)“. Setzen Sie die Grenze höher als Ihr längstes Backup oder Ihren längsten Import.
502 mit „Connection refused“. nginx findet keinen laufenden PHP-FPM hinter dem Socket. Meist wurde PHP-FPM mit fehlerhafter Datei neu geladen. Prüfen Sie /var/log/php8.4-fpm.log und starten Sie den Dienst nach der Korrektur.
Fehler 500 mit „Allowed memory size exhausted“. Das ist das memory_limit einer einzelnen Anfrage, nicht die Pool-Größe. Im Test erschien im nginx-Log „PHP Fatal error: Allowed memory size of 134217728 bytes exhausted“. Mehr Prozesse ändern daran nichts.
Slowlog bleibt leer, im Log steht „failed to ptrace(ATTACH)“. In Containern fehlt PHP-FPM oft das Recht für den Stacktrace. Die Zeilen „executing too slow“ im Hauptprotokoll nennen trotzdem das Skript.
Häufige Fragen
Wie viele Prozesse braucht eine normale Unternehmenswebsite?
Das hängt weniger von der Besucherzahl ab als davon, wie viele Seiten ohne Cache ausgeliefert werden und wie lange eine Anfrage dauert. Eine Seite, die in 0,2 Sekunden fertig ist, belegt einen Prozess nur kurz. Messen Sie Speicher und beobachten Sie die Statusseite, statt eine feste Zahl zu übernehmen.
Lohnt sich ein eigener Pool je Website?
Ja, wenn mehrere Websites auf einem Server laufen. Jeder Pool kann unter eigenem Benutzer laufen und hat eigene Grenzen. Eine überlastete Website blockiert dann nicht die anderen. Kopieren Sie dazu die Pool-Datei, vergeben Sie einen neuen Namen in eckigen Klammern und einen eigenen Socket.
Ersetzt ein großer Pool einen Seiten-Cache?
Nein. Ein Seiten-Cache liefert fertige Seiten aus, ohne PHP zu starten, und entlastet den Pool viel stärker als zusätzliche Prozesse. Lesen Sie dazu Page-Caching mit WP Super Cache einrichten.
Testumfang
Wir haben die Anleitung auf einer Testinstallation mit WordPress 7.1.2 unter Debian 13 nachgestellt und den Engpass mit einem bewusst kleinen Pool erzeugt. Die Warnung im Log und die Wartezeiten der Besucher ließen sich dabei direkt beobachten. Weil unsere Testseite leer war, fielen die Speicherwerte je Prozess niedriger aus als auf einer Website mit vielen Plugins. Echte Besucherlast haben wir nicht geprüft, messen Sie die Werte deshalb auf Ihrem eigenen Server nach.
Fazit
Ein gut eingestellter PHP-FPM-Pool beruht auf zwei Messungen: dem Speicherbedarf je Prozess und der Beobachtung, ob max children reached steigt. Damit ergibt sich pm.max_children fast von selbst, und die Betriebsart richtet sich nach Last und Speicher. Testen Sie jede Änderung mit php-fpm8.4 -t, bevor Sie neu laden. Wenn Sie Updates, Backups und die laufende Kontrolle Ihrer WordPress-Website abgeben möchten, übernimmt das die WordPress-Wartung von Marcel Schönfelder.


