How CPU & Memory Limits Impact PHP Performance in Docker (2026)

TL;DR: In I/O-bound PHP applications, reducing Docker CPU by 87% (from 4 to 0.5 vCPU) and memory by 96% (from 8 GB to 256 MB) has zero measurable impact on RPS. All configurations delivered 93–94 RPS under 50ms database latency. The bottleneck is external (database wait time), not internal (CPU or memory).

Running PHP in Docker is now standard practice, but one question persists: how much CPU and memory does your container actually need? We benchmarked PHP-FPM under various Docker resource limits — CPU quotas and memory caps — to find the breaking point. The results are surprising: in I/O-bound scenarios, resource limits barely affect throughput at all.

If your application spends most of its time waiting for databases or APIs, you may be drastically over-provisioning your containers. This benchmark shows you exactly how low you can go without impacting user experience — and when resource limits actually matter.


🧪 Test Environment

  • Server: 4 vCPU, 8 GB RAM, Ubuntu 22.04
  • PHP: 8.5.7 (OPcache + JIT tracing, buffer 128M)
  • Database: MySQL 8.4 on same host, using SLEEP(0.05) to simulate 50ms I/O latency
  • Web server: Nginx + PHP-FPM with 20 static workers (pm.max_children = 20)
  • Load generator: ab -c 50 -t 30 (50 concurrent connections, 30 seconds), 3 runs per configuration
  • Docker resource limits: Varying combinations of --cpus (0.5, 1, 2, unlimited) and --memory (256 MB, 512 MB, 1 GB, 8 GB), using host network mode (--network host) to eliminate network overhead

Business logic (identical across all tests):

  • CPU: 1000 iterations of sqrt($i) (light compute)
  • I/O: SELECT SLEEP(0.05) (simulating a 50ms database query)

This setup mimics a typical API or microservice where the bottleneck is external latency, not local processing power.


📊 Benchmark Results: Docker CPU & Memory Limits

Bar chart showing PHP-FPM RPS under different Docker CPU and memory limits, all around 93 RPS
Figure 1: PHP-FPM RPS under different Docker CPU and memory limits — all configurations deliver ~93 RPS under 50ms I/O latency.

Key finding: All values are average requests per second (RPS) over 3 runs. Each request included a 50ms database delay. Every configuration delivered 93–94 RPS — a variation of less than 1%.

Resource LimitRun 1Run 2Run 3Avg RPSvs Unlimited
Unlimited (4 vCPU / 8 GB)92.3493.8994.1093.44100%
2 vCPU / 1 GB92.4194.0093.9493.45100%
1 vCPU / 512 MB92.6294.3694.2593.74100.3%
0.5 vCPU / 256 MB92.7094.3794.5293.86100.4%
1 vCPU / 256 MB92.4394.0094.1093.51100.1%
2 vCPU / 512 MB92.3694.3494.0493.58100.1%

Core finding: Under I/O-bound workloads with 50ms database latency, Docker CPU and memory limits have virtually no impact on throughput. All 6 configurations delivered 93–94 RPS — a difference of less than 1% between the highest and lowest performing setups.

Quantified impact: Reducing CPU from 4 cores to 0.5 cores — an 87.5% reduction — resulted in 0% performance loss (93.86 RPS vs 93.44 RPS). Reducing memory from 8 GB to 256 MB — a 96% reduction — also resulted in 0% performance loss (93.86 RPS vs 93.44 RPS).


🔍 Analysis: Why I/O-Bound PHP Applications Are Resilient to Resource Limits

Bar chart comparing performance loss when resources are halved for I/O-bound, CPU-bound, and memory-bound applications
Figure 2: Performance loss when resources are halved — I/O-bound apps are virtually unaffected, while CPU and memory-bound apps show significant degradation.

The Bottleneck Is External, Not Internal

Conclusion: In I/O-intensive applications, the bottleneck is external (database latency), not internal (CPU or memory). The PHP worker spends most of its time waiting — during a 50ms SLEEP, the worker is blocked and consumes almost no CPU or memory.

Mathematical limit: With 20 workers and 50ms per request, the theoretical maximum RPS is:

Theoretical max = (1000ms / 50ms) × 20 workers = 400 RPS

Why measured throughput is ~93 RPS: The gap between theoretical (400) and measured (93) RPS is due to FastCGI, Nginx, and connection overhead. The key insight: every configuration delivered the same RPS — proving the bottleneck is external, not internal.

When Do Docker Resource Limits Actually Matter?

Our previous CPU-intensive benchmark tells a different story. Under pure CPU load, resource limits directly capped RPS because CPU time was the bottleneck.

ScenarioBottleneckImpact When Resources HalvedRecommendation
I/O-bound (database, API, network)External latencyNo impact — RPS unchanged (93.44 → 93.86)Reduce resources aggressively to save costs
CPU-bound (computation, math, image processing)Processing power⚠️ Significant impact — CPU quota directly caps RPSTest workload; start with 2 vCPU
Memory-bound (large datasets, caching)Memory capacity⚠️ Can cause OOM kills — catastrophic failureMust accommodate dataset size

Understanding your application’s primary bottleneck is essential for resource planning. I/O-bound apps are uniquely resilient to resource constraints.


🚀 Production Recommendations Based on This Benchmark

For I/O-Heavy Applications (APIs, Microservices, WordPress)

  • You can safely reduce CPU and memory quotas without impacting user-facing performance — our data shows 0% RPS change with 87% CPU reduction.
  • Recommended minimum: 1 vCPU / 512 MB per container for 20 workers (tested stable at 93 RPS).
  • Aggressive cost-saving: 0.5 vCPU / 256 MB worked in our test (93.86 RPS), but leave headroom for traffic spikes.
  • Monitor your database connection pool — that’s the real bottleneck in I/O-intensive apps.

For CPU-Heavy Applications (Image Processing, Data Crunching)

  • CPU quotas directly limit throughput — CPU = performance ceiling.
  • Start with 2 vCPU and monitor utilization; scale up if saturation occurs.
  • Memory limits must accommodate your dataset size; OOM kills are catastrophic.

General Docker Resource Guidelines

  • Use --network host for production PHP containers to eliminate NAT overhead.
  • Use CPU pinning (--cpuset-cpus) for CPU-bound workloads to prevent migration overhead.
  • Set pm.max_children based on memory: (RAM - 128MB) / 20MB per worker is a rough formula.
  • Monitor docker stats in production to validate your limits.

📌 Key Takeaways

  • I/O-bound PHP applications are remarkably resilient to resource limits. You can cut CPU by 87% and memory by 96% without losing throughput — a proven result from real benchmarks.
  • The bottleneck defines the impact. Know your application’s primary bottleneck and allocate resources accordingly.
  • Don’t overprovision for I/O-heavy workloads. Use our data to save cloud costs confidently — potentially up to 87% on CPU and 96% on memory costs.
  • Always benchmark your own application. Your database latency and workload pattern may differ.

❓ Frequently Asked Questions

Q: Does reducing Docker CPU limits affect PHP performance?
A: It depends on your workload. In I/O-bound applications (database queries, API calls), reducing CPU from 4 to 0.5 cores had zero measurable impact on RPS (93.44 vs 93.86). For CPU-bound applications (image processing, computation), CPU quotas directly cap performance.

Q: How low can I go with memory limits?
A: Our testing found that 256 MB worked perfectly for 20 PHP-FPM workers under 50ms I/O latency, delivering 93.86 RPS — identical to 8 GB. Reducing memory from 8 GB to 256 MB is a 96% reduction with no performance loss.

Q: Should I use --network host in production?
A: Yes, for PHP containers. Host network mode eliminates NAT and iptables overhead, which can improve performance by 35–60% compared to the default bridge network, as shown in our previous Docker vs bare metal benchmark.

Q: Is this data reproducible?
A: Yes. All test scripts, Dockerfiles, and raw ab outputs are available on GitHub.


📁 Reproducibility

All test scripts, Dockerfiles, and raw ab output logs are available on GitHub.

To replicate:

git clone https://github.com/phpbenchlab/docker-resource-test.git
cd docker-resource-test
docker build -t php-fpm-bench .
./run_resource_test.sh 0 0 unlimited
# ... run other configurations
cat summary.txt

🧵 Final Words

Core conclusion: In I/O-intensive PHP applications, you can dramatically reduce Docker CPU and memory limits without sacrificing performance. If your app spends most of its time waiting for databases or APIs, don’t waste money on overprovisioned containers.

Key distinction: CPU-bound tasks are a different story. Know your bottleneck, test your workload, and allocate resources accordingly.

Call to action: Have you optimized your Docker resource limits? What was your experience? Share in the comments!

Published on July 12, 2026 – Docker resource limits PHP benchmark.


🔗 Related Articles

All data from PHPBenchLab’s 2026 benchmark series. Test scripts available on GitHub.

Leave a Comment