How to fix CPU spikes and PHP-FPM slowlog on a Linux server during peak hours: diagnosis and adjustments
By Kevin Marcondes · Published on · 7 min read
Fixing CPU spikes and PHP-FPM slowlog on a Linux server during peak hours is urgent when 502/504 errors appear and traffic drops. This guide shows how to diagnose the root cause, tune PHP-FPM and the application, and set up minimal monitoring to prevent recurrence — with clear priorities to stabilize the environment under load.
Signs the bottleneck is real (and where to look first)
Under peak load, symptoms appear in sequence. Quickly validate them to avoid wrong assumptions.
Check CPU user/sys/wa, load average per core, the FPM queue and Nginx response times. Correlate with business peak times. Use dashboards with Prometheus and Grafana (/en/prometheus-grafana-docker-compose-vps) to visualize saturation by component.
- CPU at 90–100% for several minutes and load average above the number of vCPUs.
- Increase in 502/504 and high upstream_response_time in Nginx.
- Growing PHP‑FPM queue (listen.queue).
- Disk with high I/O wait (wa) and context-switch spikes (cs).
- Slowlog recording repeated backtraces for the same endpoint.
- Internal queues (jobs) lagging and overlapping cron jobs.
| Symptom | Likely cause | Next step |
|---|---|---|
| High CPU with elevated wa | Slow disk or storage I/O | Check iowait and move sessions/cache to memory |
| FPM queue growing | Too few workers or slow execution | Tune pm.* and analyze the slowlog |
| Only a few endpoints are slow | Heavy SQL, N+1 or missing cache | Optimize queries and enable caching |
| Irregular latency | PHP GC or excessive autoloading | Review memory use and autoloader |
| High load with low CPU | Blocking, I/O or kernel queues | Check iowait, run queue and locks |
Why it happens at peak? Typical bottlenecks
At peak, the system reaches concurrency limits. Small inefficiencies become queues.
The most common causes involve PHP‑FPM settings, database/IO latency and CPU cost per request.
- pm.max_children undersized or wrong process manager choice (ondemand vs dynamic).
- Slow queries and N+1 increasing average request time (see N+1 and GC diagnosis in REST APIs (/en/rest-api-latency-n1-php-gc)).
- Opcache disabled, undersized or fragmented.
- Sessions on disk, slow network storage or synchronous logging.
- Cron jobs and background workers competing with traffic for CPU.
- Heavy autoload/reflection on hot routes.
Top-down diagnosis: system → FPM → app
Frame the bottleneck before changing numbers. Following this order avoids noise in the diagnosis.
At the system level, differentiate compute CPU from I/O wait. In FPM, check the queue and worker states. In the application, identify hot handlers and queries.
- System: CPU user/sys/wa/st, load per vCPU, interrupts and steal.
- PHP‑FPM: worker status (Idle, Running, Listen queue).
- Nginx: upstream_response_time, count of 502/504 and spikes by route.
- Database: slow queries and locks during peak.
- Correlate with structured logs and request correlation (/en/structured-json-logs-request-correlation).
Enable and interpret PHP-FPM slowlog safely
The slowlog shows the backtrace of requests that exceed a threshold. Use it in short windows in production.
Set a timeout that captures slow routes without generating noise. Centralize logs for analysis with tools like Fluentd + Elasticsearch (/en/fluentd-elasticsearch-php-logs-vps).
Refer to the official FPM documentation for directive details.
- Enable slowlog for the most critical pool for a few minutes.
- Slightly increase the timeout until you capture representative cases.
- Prioritize repeated patterns in backtraces over isolated incidents.
- Cross-reference with Nginx access to find route and parameters.
; Exemplo: /etc/php/8.x/fpm/pool.d/www.conf
; Ajuste caminhos e versão de acordo com seu ambiente
request_slowlog_timeout = 3s
slowlog = /var/log/php-fpm/www-slow.log
pm.status_path = /status
catch_workers_output = yes
PHP-FPM adjustments for peak traffic (no guessing)
Size workers based on real memory consumption per process, not the theoretical memory_limit.
Choose the process manager according to traffic profile. dynamic handles predictable peaks; ondemand saves RAM at low load but may suffer cold starts.
- Estimate pm.max_children: RAM available for PHP ÷ average RAM per worker, leaving headroom for kernel, caches and the database.
- pm = dynamic with start/min/max aligned to your peak RPS.
- pm.max_requests to recycle processes and avoid constant leaks (see PHP‑FPM memory leaks (/en/php-fpm-memory-leaks)).
- listen.backlog and somaxconn set high enough for short queues without loss.
- request_terminate_timeout to kill outliers that monopolize CPU.
; Exemplo didático, ajuste pelos seus números
pm = dynamic
pm.max_children = 48
pm.start_servers = 8
pm.min_spare_servers = 8
pm.max_spare_servers = 16
pm.max_requests = 500
request_terminate_timeout = 30s
Application optimizations that relieve CPU the most
Once the bottleneck is isolated, fix the highest-cost work per request. Many improvements are quick and safe.
Focus on the hot routes found in the slowlog and application metrics.
- Enable and size Opcache (memory, interned strings, revalidation).
- Optimize the autoloader: use a generated classmap and avoid unnecessary scans.
- Eliminate N+1 and rewrite expensive queries; add proper indexes (see PostgreSQL query optimization (/en/postgresql-query-optimization-erp-reports)).
- Cache responses and fragments for hot routes; a short TTL is better than no cache.
- Reduce work per request: precompute, memoize and avoid expensive regex.
- Move heavy workers/cron jobs away from traffic peaks or limit their concurrency.
; Opcache (php.ini) — valores ilustrativos, ajuste medindo
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
opcache.validate_timestamps=1
opcache.revalidate_freq=2
Monitor and prevent recurrence
Without visibility the problem returns. Instrument system, FPM and application, and create simple alerts that fire before an incident.
Adopt dashboards focused on saturation signals and hot routes.
- System metrics: CPU user/sys/wa, load per vCPU, iowait, run queue.
- FPM: workers by state, listen.queue, spawn rate and 5xx by route.
- Correlated logs by request_id and archived samples of slowlog.
- APM/tracing for critical routes and jobs during peak hours.
- Periodic load tests with realistic data and cold/hot cache scenarios.
Frequently asked questions
What does the PHP-FPM slowlog actually show?
It records a backtrace when a request exceeds request_slowlog_timeout. You then see which functions and code paths were running. Enable it in short windows to avoid excess logging and focus on repeated patterns.
Is pm.dynamic or pm.ondemand better for peaks?
It depends on the profile. Dynamic keeps processes warm and handles predictable peaks better. Ondemand saves RAM at low load but may suffer cold starts when load rises quickly. Test with your traffic and monitor the FPM queue.
How to safely calculate pm.max_children?
Measure the average memory of a worker under real load and leave headroom for kernel, caches, Nginx and the database. Divide the RAM available for PHP by the average worker usage. Don’t rely on memory_limit alone—it’s a ceiling, not real usage.
Can slow queries cause CPU spikes?
Yes. Unoptimized queries increase request time and tie up workers, raising the queue and CPU usage. Fix N+1, add indexes, review execution plans and consider caching expensive results for hot routes.
When should I consider scaling servers?
After optimizing and right-sizing FPM, Opcache and hot routes. If average utilization during peaks remains high with growing queues, add vCPUs and RAM or scale horizontally. Load tests help validate the saturation point.
Want to stabilize your peak traffic?
If you need a technical review to diagnose CPU spikes and PHP-FPM slowlog and define safe adjustments, let's talk about your case.
Schedule a callSee also
- Intermittent 502 Bad Gateway in Docker Compose with Nginx & PHP‑FPM: how to diagnose and fix timeouts and connection overloads
- How to diagnose and capture packets for intermittent network issues between Docker containers on Debian
- How to detect and fix duplicate SKU inconsistencies between WooCommerce and your ERP without losing orders
- How to reduce build time and avoid duplicate artifacts in CI for large PHP monoliths