Run sudo php-fpm8.3 -t (match your version). PHP-FPM has a real configuration test and it names the file and line that broke. Fix that line, then sudo systemctl reload php8.3-fpm. The systemd message tells you nothing on its own.
$ sudo php-fpm8.3 -t [04-Oct-2026 11:02:13] ERROR: [/etc/php/8.3/fpm/pool.d/www.conf:4] unknown entry 'pm.max_childern' [04-Oct-2026 11:02:13] ERROR: Unable to include /etc/php/8.3/fpm/pool.d/www.conf from /etc/php/8.3/fpm/php-fpm.conf at line 143 [04-Oct-2026 11:02:13] ERROR: failed to load configuration file '/etc/php/8.3/fpm/php-fpm.conf'
Check the exit code before anything else
PHP-FPM is unusual among these services because its exit code is genuinely diagnostic. systemctl status php8.3-fpm showing status=78/CONFIG means the daemon rejected its own configuration and nothing else is worth investigating until that is fixed. That one number separates a configuration problem from everything else on this page.
systemctl status php8.3-fpm | grep -E 'Process|status=' sudo journalctl -xeu php8.3-fpm.service --no-pager | tail -40
The causes, in order of how often they appear
- A typo in the pool section header. The classic is
[wwww]instead of[www]inpool.d/www.conf, usually from a stray keystroke. FPM accepts the file but then has no pool matching what the rest of the stack expects, or fails outright. Because the header looks almost right, people read past it repeatedly. Check the first line of every file inpool.d/. - Two pools with the same name. FPM refuses to start if two files in
pool.d/declare the same section, which happens when a pool is copied to a new file and the header is never changed. The error names the duplicate. - The socket is already in use by another PHP version. The single most common cause on servers running more than one PHP release. An old
php8.1-fpmstill holds the socket or port the new pool wants:systemctl list-units 'php*-fpm*' --all sudo ss -lxp | grep php
Either stop the old version or give each pool its own socket path. Two FPM versions pointed at one socket will fight every time either restarts.
- The listen directory does not exist. FPM creates the socket file but not the directory above it. A pool listening on
/run/php/app/fpm.sockfails ifapp/was never created. Note that anything under/runis a tmpfs and disappears on reboot, so a directory created by hand will vanish and the failure returns after the next restart. Create it from a tmpfiles rule instead. - The user or group in the pool does not exist. Copying a pool from another host brings its
user =andgroup =with it. If that account is not present, FPM exits during initialisation.
When the config test passes but the service still fails
A clean -t rules out syntax, unknown entries and duplicate pools, because the test parses every pool file. What it does not do is bind sockets or resolve users, so causes 3, 4 and 5 above all pass the test and fail at startup. If -t is clean, go straight to the journal and look for a bind or permission line rather than re-reading the configuration.
One more possibility worth knowing: if the journal shows nothing at all, check systemctl cat php8.3-fpm for a drop-in. A unit override with a wrong ExecStart path produces 203/EXEC and no FPM logs whatsoever, because the binary never ran. The full exit-code table is in the nginx version of this error.
How to stop it happening again
Test before you apply, and reload rather than restart. The test exits non-zero on a bad configuration, so chaining on && means a broken pool never reaches the running daemon:
sudo php-fpm8.3 -t && sudo systemctl reload php8.3-fpm
A reload keeps existing workers serving requests while the new pool configuration comes up, so a mistake costs nothing. A restart drops every in-flight request first, which on a busy site turns a typo into visible errors for real users.
Related
- Job for nginx.service failed: the web server half of the same stack, plus the full exit-code table.
- Job for apache2.service failed: the same failure on Apache.
- nginx rewrite rule generator: build the rewrite and proxy blocks that sit in front of an FPM pool.
What does status=78/CONFIG actually mean?
78 is the conventional Unix exit code for a configuration error, defined as EX_CONFIG. PHP-FPM uses it deliberately, so seeing it in systemctl status is a definitive statement that the daemon read its configuration and rejected it. Run php-fpm8.3 -t and the specific line will be named. Any other status means the configuration was accepted and the failure happened later.
nginx returns 502 but FPM is running
That is a different failure from this page. If systemctl is-active php8.3-fpm reports active, FPM started correctly and the problem is the connection between nginx and the pool. Compare the listen = path in the pool file against the fastcgi_pass in the nginx site: a version upgrade that changed the socket from php8.1 to php8.3 while the nginx config still points at the old path is the usual cause.
Leave a Reply