2026年11月12日

2026年11月12日

Apache Connection Limits: MaxRequestWorkers, ServerLimit, Backlog

This article is a localized edition of the Japanese original. Read the Japanese original

How many connections Apache can handle at once is set by the MPM (Multi-Processing Module) configuration. The key directive is MaxRequestWorkers; connections beyond it go into a queue. Too low a limit makes visitors wait during traffic spikes, while too high a limit can exhaust memory and destabilize the whole server.

This article explains the Apache 2.4 settings that limit concurrent connections, how to choose values, and how to check whether you are hitting the limit. Default values are based on the official Apache 2.4 documentation as of October 2026.

Check the MPM first

The same directive can mean different things and have different defaults depending on the MPM. First check which MPM you are running.

# Debian/Ubuntu
sudo apachectl -V | grep -i mpm

# RHEL-based systems (AlmaLinux, Rocky Linux, etc.)
sudo httpd -V | grep -i mpm
MPM Unit of work Characteristics
event Processes + threads Can detach connections waiting on KeepAlive from threads. The default on major distributions as of October 2026
worker Processes + threads One thread handles one connection
prefork Processes only One process handles one connection. Used with modules that are not thread-safe (such as mod_php)

The differences between MPMs and how to choose one are covered in Apache worker, prefork and event: differences and how to choose.

Settings that affect concurrent connections

Setting Meaning Default
MaxRequestWorkers The maximum number of requests served at the same time. Connections beyond it are queued (called MaxClients before Apache 2.3.13) prefork: 256; event and worker: 400 (ServerLimit 16 × ThreadsPerChild 25)
ServerLimit The maximum number of child processes. With prefork it is the ceiling for MaxRequestWorkers 256 for prefork, 16 for event and worker
ThreadsPerChild The number of threads each child process creates (event, worker) 25
ThreadLimit The ceiling for ThreadsPerChild (event, worker) 64
ListenBacklog The length of the queue of connections waiting to be handled 511
MaxConnectionsPerChild The number of connections a child process handles over its lifetime. After that the process exits and is replaced (formerly MaxRequestsPerChild) 0 (never exits)

Watch out for MaxConnectionsPerChild. Its name is often taken to mean a per-process limit on concurrent connections, but it has nothing to do with concurrency. It is a setting for recycling processes periodically, and you set it to a non-zero value when a module or PHP leaks memory and processes keep growing.

Likewise, Listen 80 only specifies the port to listen on; it does not limit the number of connections.

Where the configuration lives

Distribution Choosing the MPM Where to put MPM settings
Debian/Ubuntu a2enmod / a2dismod (mpm_event etc.) /etc/apache2/mods-available/mpm_event.conf (mpm_prefork.conf for prefork)
RHEL-based The LoadModule line in /etc/httpd/conf.modules.d/00-mpm.conf Create a file such as /etc/httpd/conf.d/mpm.conf and put them there

On RHEL-based systems, .conf files in /etc/httpd/conf.d/ are loaded from httpd.conf.

Example settings for event and worker

With event and worker, the number of requests you can handle at once is the total number of threads. Choose values that satisfy these relationships:

  • MaxRequestWorkers ÷ ThreadsPerChild = the number of child processes, which must not exceed ServerLimit
  • Make MaxRequestWorkers a multiple of ThreadsPerChild (otherwise it is rounded down at startup with a warning)
  • ThreadsPerChild must not exceed ThreadLimit

With the default ServerLimit of 16 and ThreadsPerChild of 25, the limit is 400. To go up to 800 you need 32 child processes, so raise ServerLimit to 32 as well.

<IfModule mpm_event_module>
    StartServers             2
    ServerLimit              32
    ThreadLimit              64
    ThreadsPerChild          25
    MaxRequestWorkers        800
    MinSpareThreads          25
    MaxSpareThreads          75
    MaxConnectionsPerChild   0
</IfModule>

The mpm_event.conf shipped in the Debian/Ubuntu package sets MaxRequestWorkers to 150 (it has no ServerLimit line, so the default of 16 applies).

Example settings for prefork, and sizing from memory

With prefork, one process handles one connection, so the number of concurrent connections is the number of processes. With mod_php, a single process using tens of megabytes of memory is not unusual. Work out the limit backward from the amount of memory.

# Average memory use per Apache process (MB). On RHEL-based systems, replace apache2 with httpd
ps -C apache2 -o rss= | awk '{sum+=$1; n++} END {if (n) printf "%d processes, avg %.1f MB\n", n, sum/n/1024}'

# Memory for the whole server
free -m

For example, if Apache may use 2 GB (after setting aside memory for the database and the OS) and the average process uses 50 MB, the guideline is 2048 ÷ 50 ≈ 40. Use values measured during your busiest hours.

<IfModule mpm_prefork_module>
    StartServers             5
    MinSpareServers          5
    MaxSpareServers         10
    MaxRequestWorkers       40
    MaxConnectionsPerChild   0
</IfModule>

To set MaxRequestWorkers above 256 with prefork, raise ServerLimit to at least the same value.

ListenBacklog and the OS limit

Once MaxRequestWorkers is reached, further connections wait in the OS queue for a free slot. The length of this queue is ListenBacklog. The OS has its own ceiling, though: on Linux it cannot exceed net.core.somaxconn.

sysctl net.core.somaxconn

A longer queue does not increase how much you can process. Queued connections eventually time out. Review MaxRequestWorkers and how fast requests are processed before lengthening the queue.

How KeepAlive interacts

With KeepAlive enabled, a connection stays open while it waits for the next request (KeepAliveTimeout, 5 seconds by default). With prefork and worker, that waiting time also occupies a process or thread, so you reach the limit sooner. The event MPM detaches waiting connections from threads, so it is much less affected. For details, see Optimizing connections with Apache's KeepAlive settings.

Balancing with PHP-FPM

When Apache hands PHP off to PHP-FPM (event + mod_proxy_fcgi), how many PHP requests can run at once is set not by Apache but by the PHP-FPM pool setting pm.max_children. Writing something like php_value max_children in the Apache configuration has no effect (php_value is mod_php syntax, and PHP has no setting named max_children).

Set it in the PHP-FPM pool configuration file (/etc/php/8.3/fpm/pool.d/www.conf for PHP 8.3 on Debian/Ubuntu as of October 2026, or /etc/php-fpm.d/www.conf on RHEL-based systems).

pm = dynamic
pm.max_children = 20
pm.start_servers = 4
pm.min_spare_servers = 2
pm.max_spare_servers = 6
sudo systemctl reload php8.3-fpm   # php-fpm on RHEL-based systems

If Apache's MaxRequestWorkers is much larger than pm.max_children, Apache accepts connections but the PHP work waits for a free PHP-FPM process. If the PHP-FPM log contains the warning "server reached pm.max_children setting", the PHP side is at its limit. Size pm.max_children from the memory used per PHP-FPM process as well. Integrating with PHP-FPM is covered in How to connect Apache with PHP-FPM.

Apply the settings

# Check the syntax
sudo apachectl configtest

# Apply (Debian/Ubuntu; httpd on RHEL-based systems)
sudo systemctl restart apache2

ServerLimit and ThreadLimit are not changed by a graceful reload (systemctl reload). When you change them, stop and start the server with systemctl restart.

Check whether you are hitting the limit

Error log

When MaxRequestWorkers is reached, Apache writes an entry like the following to its error log (AH00484 for event, AH00161 for prefork).

server reached MaxRequestWorkers setting, consider raising the MaxRequestWorkers setting
# Debian/Ubuntu; /var/log/httpd/error_log on RHEL-based systems
sudo grep -i "MaxRequestWorkers" /var/log/apache2/error.log

mod_status

With mod_status enabled, you can see the number of busy workers (BusyWorkers) and idle workers (IdleWorkers). Restrict /server-status so it can be viewed only from the server itself.

<Location "/server-status">
    SetHandler server-status
    Require local
</Location>
curl -s "http://localhost/server-status?auto" | grep -E "BusyWorkers|IdleWorkers"

If BusyWorkers sits at MaxRequestWorkers during busy hours, the limit is too low. If you have spare memory, raise it; if not, shorten the time each request takes by adding caching or improving heavy pages. Reading mod_status is covered in Checking server status with Apache's mod_status.

Limiting connections per IP address

Everything above is a server-wide limit. To curb large numbers of connections from a particular IP address, note that Apache 2.4's standard modules have no directive that limits concurrent connections per IP address. Use a third-party module.

Summary

  • The limit on concurrent processing is MaxRequestWorkers. With event and worker it is bounded by ServerLimit × ThreadsPerChild
  • With prefork, work out the limit from the memory used per process
  • MaxConnectionsPerChild (formerly MaxRequestsPerChild) is the number of connections before a process is recycled, not a concurrency limit
  • ListenBacklog is the queue length, capped by the OS's net.core.somaxconn. It does not increase throughput
  • With PHP-FPM, PHP concurrency is set by pm.max_children. It cannot be set with php_value
  • After changing ServerLimit or ThreadLimit, apply with restart, and check the error log and mod_status to make sure you are not hitting the limit

Questions about WordPress? The publisher of this site is based in Japan and replies in Japanese. Contact (Japanese)

お気軽にご相談ください

お見積りへ お問い合わせへ
▲