skip to content

Status & Slow Logs

The PHP-FPM status page reports active processes, the listen queue and max children reached, and the slow log dumps stuck requests' stacks. Interviewers ask how you diagnose a saturated pool.

on this pageshow

explore

questions

5

What does PHP-FPM's request_terminate_timeout do to a long request, and how does it relate to PHP's max_execution_time?

level: middleimportance: should knowfreq 35%

answer

  1. default 0: off
  2. master kills the worker with SIGTERM
  3. web server sees a 502
  4. backstop when max_execution_time does not stop it
  5. track_finished covers post-response work

basics

~20 s

request_terminate_timeout makes the FPM master kill a worker whose request runs past the limit; the client usually gets a 502 and a replacement is forked. Off by default, it backstops PHP's max_execution_time, which raises an error inside the script instead.

solid answer

~50 s

`request_terminate_timeout` is a per-pool limit (default `0`, off; units `s`, `m`, `h`, `d`) enforced from **outside** PHP: the FPM master watches wall-clock time since the request was accepted, and when it is exceeded it logs `execution timed out (… sec), terminating` and sends the worker SIGTERM. The request ends without a complete response, so the web server typically returns 502; the worker's exit is logged and a replacement is forked. `max_execution_time` works **inside** PHP and ends the script with a fatal error and normal cleanup, but it does not always stop a script — the FPM sample configuration names this directive as the fallback for that case. By default the timeout stops applying once the script calls `fastcgi_finish_request()` or is running shutdown functions; `request_terminate_timeout_track_finished = yes` keeps it engaged. Set it above your slowest legitimate request and above `request_slowlog_timeout`.

code

ini · 11 lines
ini
[shop]
request_slowlog_timeout = 3s
slowlog = /var/log/php-fpm/$pool.slow.log
; hard backstop, above normal pages
request_terminate_timeout = 30s
; also cover work after fastcgi_finish_request()
request_terminate_timeout_track_finished = yes

[reports]
; long exports get their own pool and limit
request_terminate_timeout = 300s

go deeper

for a junior

Recall that request_terminate_timeout makes PHP-FPM kill a request that runs too long, and that it is off by default.

for a middle

Contrast it with max_execution_time: outside versus inside PHP, SIGTERM versus a fatal error, a 502 versus a PHP error page, no cleanup versus shutdown functions.

for a senior

Set it deliberately: above legitimate slow requests, near the web server's timeout, above the slowlog threshold, with track_finished for post-response work.

for a principal

Define timeout budgets across tiers so the web server, FPM and PHP limits fail in a known order with known user-facing results.

## Two limits at two levels PHP-FPM offers a time limit that sits **outside** the PHP engine: | | `request_terminate_timeout` | `max_execution_time` | |---|---|---| | Configured in | The FPM pool file | php.ini, pool `php_value`, `ini_set()` | | Enforced by | The FPM **master** process | The PHP engine inside the worker | | How it stops a request | Kills the worker process (SIGTERM) | Raises a fatal error in the script | | What the client sees | Usually 502 from the web server | Whatever PHP sends — often a 500 page | | Cleanup | None: the process is gone | Shutdown functions still run | | Default | `0` (off) | Set in php.ini | `max_execution_time` belongs to PHP's runtime configuration; what matters here is that it does not always stop a script, and the PHP-FPM sample configuration describes `request_terminate_timeout` as the option to use "when the 'max_execution_time' ini option does not stop script execution for some reason". ## What happens when it fires 1. The master measures time since the worker **accepted** the request. 2. Once it exceeds the limit, the master sends the worker **SIGTERM** and logs a WARNING: `[pool shop] child 8790, script '/srv/shop/public/index.php' (request: "POST /checkout/confirm") execution timed out (30.001204 sec), terminating` 3. The worker dies mid-request: an open database transaction is left for the database to roll back when the connection drops, half-written files stay half-written, and no `finally` block or shutdown function runs. 4. The master logs the child's exit — `exited on signal 15 (SIGTERM)`, at WARNING level — and forks a replacement so the pool stays at size. 5. The web server's FastCGI connection closes without a complete response, which it normally reports as **502 Bad Gateway**. ## The track_finished switch By default the timeout is **not** engaged once the application has called `fastcgi_finish_request()` or has finished and is running shutdown functions registered with `register_shutdown_function()`. So a hung post-response task can hold a worker indefinitely. Setting `request_terminate_timeout_track_finished = yes` (available since PHP 7.3) applies the limit unconditionally. ## Interaction with the slow log `request_slowlog_timeout` must not be greater than a non-zero `request_terminate_timeout` — FPM rejects that configuration — because a request would be killed before its backtrace could be logged. The useful layout is slow log first, termination later: for example 3 s to log, 30 s to kill. ## Choosing a value - **Above legitimate slow requests.** Exports and reports that take 60 s will be killed at 30 s; give them a separate pool with a higher limit instead of raising it for everyone. - **Aligned with the web server.** If the web server gives up at 60 s (a 504) and FPM kills at 300 s, the worker keeps running for four minutes after anyone is listening. Setting FPM's limit near the web server's timeout frees workers sooner. - **Not a substitute for fixing slowness.** Each kill is a user-facing error and a lost worker; the slow log shows what to fix. ## Related global settings Two settings in `php-fpm.conf` concern failing workers rather than slow ones: - `emergency_restart_threshold` and `emergency_restart_interval` (both `0`, off, by default): if that many workers exit on SIGSEGV or SIGBUS within the interval, FPM reloads itself. - `process_control_timeout` (default `0`): the time limit for child processes to wait for a reaction on signals from the master, relevant to graceful reloads. ## Where to see it happening - **FPM error log:** each kill is a pair of WARNING lines — `execution timed out (… sec), terminating` with the pool, PID, script and request, then the child's `exited on signal 15 (SIGTERM)` line. - **Web server log:** a 502 at the same moment, with an error about the upstream closing the connection before a complete response. - **Status page:** nothing specific, but `active processes` drops by one and the replacement worker appears. Counting the terminating lines per hour is a simple alert: any sustained rate means users are getting errors. ## Summary `max_execution_time` is PHP's polite limit — an error inside the script. `request_terminate_timeout` is FPM's hard limit — the process is killed from outside. Production pools usually set both, with the FPM limit comfortably above the PHP one so that it only fires when the polite limit fails.

  • A request killed by request_terminate_timeout did not run its finally block or shutdown function. Why?
    The FPM master ends the worker with SIGTERM from outside the engine, so no PHP code runs afterwards: no `finally`, destructors or shutdown functions. That differs from PHP's own time limit, which raises a fatal error inside the script, after which shutdown functions still run.
  • A worker stays busy for minutes after calling fastcgi_finish_request(), despite request_terminate_timeout = 30s. Why?
    By default the terminate timeout is not engaged after `fastcgi_finish_request()` or while shutdown functions run. Set `request_terminate_timeout_track_finished = yes` so the limit applies to the whole lifetime of the request, including post-response work.

saying these in an interview costs you the question

  • request_terminate_timeout raises a catchable error inside the script
  • Shutdown functions still run after the FPM master kills the worker
  • request_terminate_timeout is enabled by default at 30 seconds
  • The killed worker leaves the pool one process short
  • It always applies after fastcgi_finish_request()
open as a page

How do PHP-FPM's request_slowlog_timeout and slowlog work, and what does a slow-log entry show?

level: middleimportance: should knowfreq 38%

basics

~20 s

When a request has run longer than request_slowlog_timeout, the FPM master pauses that worker, reads its PHP call stack and appends it, with the script path, to the pool's slowlog file; the request then continues. It is off by default and needs slowlog set.

open as a page

What do the PHP-FPM status page's active processes, listen queue and max children reached fields tell you about a pool?

level: middleimportance: should knowfreq 42%

basics

~20 s

Active processes counts workers busy right now; listen queue counts connections waiting for a free worker; max children reached counts how often the pool wanted to grow past pm.max_children. Busy workers at the cap plus a non-zero queue means a saturated pool.

open as a page

During a flash sale, a PHP site behind PHP-FPM returns intermittent 502s; how do you use FPM's status page and logs to find the cause?

level: seniorimportance: should knowfreq 45%

basics

~20 s

A 502 means the web server got no valid FastCGI response. Line up its timestamps with the FPM status page (all workers busy, queue near its length) and the FPM log (terminations, crashes), then read the slow log for what workers wait on.

open as a page

What does PHP-FPM's ping.path endpoint check, and why is it not a full application health check?

level: juniorimportance: nice to knowfreq 22%

basics

~20 s

ping.path makes a PHP-FPM pool answer that URI with a plain-text 'pong' (ping.response) and status 200. It proves the web server can reach the pool and a worker is free, but runs no application code, so it cannot detect a broken database or app.

open as a page