Skip to main content

PHP-FPM slowlog: how to find slow scripts

PHP · 18.10.2026 · 4 min read
Illustration for “PHP-FPM slowlog: how to find slow scripts”

The PHP-FPM slowlog captures the call stack of a request at the moment it has been running longer than a set threshold — a snapshot of one stuck point of execution, not a continuous trace. There was no article in the catalog for reading that snapshot and telling slow code apart from a slow database.

What slowlog writes, and what it does not

If a request runs longer than request_slowlog_timeout, PHP-FPM dumps the call stack trace once — which function and line were executing at the moment of the snapshot. That is unlike a regular error_log: it shows a message after the script finishes, while slowlog shows what is happening in real time, while the process is still alive.

The snapshot does not contain a history of calls over time — only one slice at the moment of the timeout. How messages end up in error_log and in fatal output is covered separately in the article on PHP logs.

Enabling slowlog in the pool configuration

The directives live in the pool configuration, next to the other PHP-FPM settings covered in the article on PHP-FPM pools and workers. request_slowlog_timeout sets the threshold after which the trace is taken, and slowlog is the path to the file.

The threshold should match the expected response time of a specific endpoint: for an ordinary page 5 seconds is already suspiciously long, while for a background heavy report the same threshold fires on every request and fills the log with useless traces.

How to read the trace

The entry shows a chain of function calls with line numbers — the outermost call on top, the current, stuck function at the bottom. If the bottom call is a file, network or database function, the script is most likely waiting on an external resource rather than doing CPU work.

  • an outbound HTTP call to an API with no timeout or a large one
  • a database query without an index — a recognizable PDO or mysqli call chain
  • a loop with N+1 queries, where every iteration waits for a separate database reply
  • a regular expression with catastrophic backtracking on a long string
  • waiting on a file lock held by another process

Table of the main slowlog parameters

The values in the table are a starting point, not a universal standard: the threshold is tuned to the profile of a specific endpoint.

ParameterWhat it doesTypical starting value
slowlogpath to the trace file/var/log/php8.3-fpm-slow.log
request_slowlog_timeoutthreshold after which a trace is written5s
request_terminate_timeoutforce-kills a stuck request30s
slowlog_timeout_depthstack depth in the trace entry128

Slowlog versus the MySQL slow query log

If the trace bottoms out in a PDO or mysqli call, that points to a slow database query, not slow PHP code. In that case an exact diagnosis comes from the database's own slow query log — enabling and reading it is covered in the article on the MySQL Slow Query Log, which shows the SQL itself and the number of rows scanned.

Rotation: slowlog grows fast with a low threshold on a busy site, so the file should go into logrotate the same way regular Nginx and PHP logs do, otherwise it will take up all the free disk space.

slowlog = /var/log/php8.3-fpm-slow.log
request_slowlog_timeout = 5s
request_terminate_timeout = 30s

Frequently asked questions

Is it fine to leave slowlog enabled permanently in production?

Yes, if the threshold is reasonable: a trace is written only when a request exceeds the threshold, so a permanently enabled slowlog with a 5 second threshold does not load the server on ordinary fast requests.

Why is the trace empty or cut off at the first line?

Most often this is too small a slowlog_timeout_depth value: it limits the stack depth, and if the stuck call is deeper than that limit, the trace is simply cut off.

The trace shows a curl_exec call, what should be done?

That is an outbound HTTP call with no timeout or a large one — the fix is to add or lower the timeout of that call itself, not to raise request_slowlog_timeout, which only hides the symptom.

Was this article helpful?
← Back to Knowledge Base Ask Support