You Patched PHP. Did You Restart It?
Installing a fixed package replaces files on disk; running processes keep the old code. How PHP-FPM reloads behave, which long-running PHP processes get forgotten, and how to prove everything runs the new binary.
A package upgrade changes files. It does not change code that is already running. PHP's own October 2026 advisories make the point in their mitigation sections: after changing anything, "restart every PHP worker". This guide covers what that means in practice.
PHP-FPM: a reload is enough — and here is how to prove it
systemctl reload php8.4-fpm sends the master process a graceful reload. The master re-reads its configuration and replaces every worker. Two things confuse people when they check afterwards:
- The master keeps its PID and its original start time. It does not handle requests.
- The workers are new. Their start time is after the reload.
Check the workers, not the master:
ps -eo pid,lstart,args | grep 'php-fpm: pool' | grep -v grep | head
Every worker should have started after the moment you upgraded or reloaded. You can find that moment in /var/log/dpkg.log or with systemctl status.
The processes everyone forgets
Anything that runs PHP for a long time keeps the binary it started with:
- queue workers (
php artisan queue:work, Symfony Messenger consumers) - schedulers and daemons started by supervisor or systemd
- application servers such as Octane, RoadRunner or Swoole
- websocket servers written in PHP
- agents and monitoring tools that run on PHP CLI
When a package replaces the binary on disk, the kernel shows the old one as deleted for processes that still use it:
for p in $(pgrep -f 'php'); do
printf '%s %s\n' "$p" "$(readlink /proc/$p/exe)"
done | grep deleted
Any line ending in (deleted) is a process still running the old interpreter. On Ubuntu, needrestart performs the same check across all services and is often installed already.
Restart without losing work
- Laravel queues:
php artisan queue:restartasks each worker to exit after its current job; your process manager starts a new one. - supervisor:
supervisorctl restart <program>(orall), with a sensiblestopwaitsecsso jobs can finish. - systemd services:
systemctl restart <unit>. - Cron-started workers that a guard script relaunches: signal them to stop gracefully, and the next cron run starts them on the new binary.
Then verify again with the (deleted) check above. An empty result is the evidence you want.
Does it matter for the CLI?
Be precise about risk. The October 2026 PHP vulnerabilities are reached through request handling: multipart body parsing and state left between requests in a web worker. A queue worker that never parses an HTTP request is a much smaller target than a PHP-FPM pool. Restarting it is still the right default, because next month's vulnerability may sit somewhere else, and "everything runs the patched binary" is a statement you can verify, while "this process probably isn't exposed" is not.
A side effect to expect: cold caches
Right after a reload, OPcache is empty and every script is compiled again. On one application we saw a single 502 immediately after a reload. The cause was not the patch: the code emitted PHP deprecation notices on first compile, the notices were sent towards the response headers, and nginx rejected the upstream with "upstream sent too big header". It cleared on the next request. If your logs show deprecation notices today, fix them, or at least make sure display_errors is off in production so notices go to the log rather than into the response.
A short checklist
- Upgrade packages; confirm the version with
php-fpm8.x -v. - Reload every PHP-FPM version you run, not just the main one.
- Restart long-running PHP processes: queues, daemons, agents.
- Confirm that no
(deleted)binaries remain and that every worker started after the upgrade. - Smoke-test your sites and compare the result with what you saw before the change.
Sources
- GHSA-6wmf-4rv5-p3rp — mitigation section (restart every worker) — php-src
- GHSA-w8hw-w9fx-j79w — mitigation section — php-src
- PHP-FPM configuration — php.net
- Laravel queues — queue workers and deployment — Laravel