Skip to content
EdgeServers
Blog

Apache MPM event in 2026 — sizing the thread pool we actually run

May 13, 2026 · 1 min read · by Sudhanshu K.

This is a snippet. The full article lives on Medium.

Every time we onboard a new customer running Apache httpd, the first thing we look at is the MPM configuration. About 70% of the time it's still prefork, usually because the install was bootstrapped years ago when someone needed mod_php and never revisited. Another 20% is worker with default numbers from the distribution package. Maybe 10% is event — and of those, perhaps half are sized appropriately.

The three MPMs, briefly

  • prefork — one process per request, no threads. Huge memory footprint. Survived because mod_php is not thread-safe.
  • worker — multiple processes, each with multiple threads. A thread is occupied for the whole connection lifetime, including idle keep-alive.
  • event — same threads as worker, but idle keep-alive connections are handed back to a dedicated listener using epoll/kqueue. A thread is occupied only while it's actually doing work.

For keep-alive workloads — and HTTP/2 means everything is keep-alive in 2026 — event is materially better than worker. On a busy site with 5,000 concurrent connections, that's the difference between needing 5,000 threads and needing maybe 400.

The numbers that actually matter

What we deploy on a typical 4-vCPU / 8 GB Apache box serving PHP-FPM:

<IfModule mpm_event_module>
    ServerLimit              16
    ThreadsPerChild          64
    MaxRequestWorkers        1024
    MaxConnectionsPerChild   10000
    AsyncRequestWorkerFactor 2
</IfModule>

MaxRequestWorkers is the famous knob — but on event it controls active workers, not total connections. AsyncRequestWorkerFactor is the multiplier that lets the listener hold many more idle keep-alives than MaxRequestWorkers would suggest.

The full Medium post walks through:

  • Why prefork has to go (and the PHP-FPM migration that replaces mod_php)
  • How to size ServerLimit × ThreadsPerChild against your actual concurrency
  • The MaxConnectionsPerChild reasoning — and why the default of 0 is wrong
  • Reading mod_status + apachetop to verify your tuning under real load
  • Where event still loses to nginx, and where it doesn't

Continues on Medium.