📑 Daftar Isi
- Introduction
- Symptoms of Apache Slots Being Full
- Root Cause: Why Do Apache Slots Run Out?
- 1. Websites with Slow PHP Execution
- 2. PHP-FPM Timeout Not Configured
- 3. Traffic Spike or DDoS
- 4. KeepAlive Timeout Too Long
- 5. Aggressive Bots or Crawlers
- Command #1: View All Apache Slot Status
- Command #2: Identify the Website Consuming the Most Slots
- Command #3: Check Slots in Waiting or Stuck State
- Command #4: Count Total Slots Used vs Available
- How to Fix Apache Slots Being Full
- ⚠️ SECURITY WARNING: Backup Configuration Before Making Changes
- Solution 1: Optimize KeepAliveTimeout
- Solution 2: Increase MaxClients (If RAM Allows)
- Solution 3: Block Aggressive IPs
- Solution 4: Disable xmlrpc.php (If Not Needed)
- Solution 5: Add Rate Limiting to Apache
- Pro Tips: Preventing Apache Slots from Filling Up
- FAQ
- What's the ideal MaxClients for a cPanel server?
- What's the difference between 503 Service Unavailable and 502 Bad Gateway?
- How do I know if slots are full due to a DDoS attack?
- Is it safe to restart Apache in production?
- Related Issues
- Conclusion
Introduction
Last week at 2 AM, my phone buzzed — monitoring notification: “HTTP 503 on client X’s main website.” What made it frustrating was that this client had just migrated from shared hosting to a dedicated VPS, and they had 12 active websites on one server. The moment I SSH’d in, I immediately knew the problem: Apache slots were full. All workers were occupied, and new requests were being flat-out rejected.
The first time I encountered this kind of problem, I was confused because a 503 error can mean many things — database down, PHP-FPM crash, even Nginx misconfiguration. But once I checked server-status, it became crystal clear: all 256 Apache slots were filled, and to make matters worse, some slots had been waiting over 60 seconds with zero progress. That meant stuck requests were blocking slots for other requests.
From that experience, I learned how to read Apache server-status correctly, identify which requests were stuck, and most importantly — find which website was consuming the most slots. All using simple but powerful commands. In this article I’ll show you these methods in full detail.
Symptoms of Apache Slots Being Full
Before troubleshooting, it’s important to know the symptoms that indicate Apache is running out of slots:
- Error 503 Service Unavailable — the most classic symptom. The website suddenly becomes inaccessible and the server returns a 503 error.
- Website loads extremely slowly — requests can get through but have to wait in a very long queue because slots are full.
- Some websites down while others are still alive — this happens because one or more websites are consuming excess slots, blocking other websites on the same server.
- Apache log full of “MaxClients reached” errors — if you check the error log, you’ll see messages like
[notice] MaxClients of 256 servers not reached, some servers could not be allocated. - RAM completely used up — each Apache slot consumes RAM. If slots are full and RAM runs out, the server can start swapping or even trigger the OOM killer.
- CPU load rises but requests don’t complete — this indicates requests are stuck at a certain stage (waiting for database, waiting for external API, or stuck in PHP execution).
Root Cause: Why Do Apache Slots Run Out?
Apache slots don’t fill up on their own. There’s always a cause, and from my experience, here are the most common ones:
1. Websites with Slow PHP Execution
Slow PHP websites — whether from unindexed database queries, infinite loops, or time-consuming extensions — hold slots longer than they should. A single request executing for 30 seconds means that slot is locked for 30 seconds. If there are 10 such requests simultaneously, that’s 10 slots gone.
2. PHP-FPM Timeout Not Configured
If Apache is configured with mod_php or PHP-FPM without proper timeouts, stuck requests will keep consuming slots until Apache itself times out. The default Apache timeout is usually 300 seconds — way too long.
3. Traffic Spike or DDoS
Sudden traffic spikes — whether from a marketing campaign, viral content, or a DDoS attack — can instantly drain all slots within seconds.
4. KeepAlive Timeout Too Long
A KeepAliveTimeout configuration that’s too long (e.g., 15 seconds) keeps slots occupied even after the client has stopped being active. The client loads the page, finishes, but the slot is held for another 15 seconds.
5. Aggressive Bots or Crawlers
Bots crawling a website too aggressively without delays can exhaust slots in a short time. Especially if the bot is executing JavaScript or waiting for responses from complex pages.
Command #1: View All Apache Slot Status
The first step when you suspect Apache slots are full is to view the status of all active slots. From here we can see which slots are in use, which are idle, and which are stuck.
For cPanel servers, we can access status through WHM server status. Here’s the command:
links --dump 1 http://localhost:80/whm-server-status|grep ^[0-9]|awk 'BEGIN {print "Seconds, PID, State, IP, Domain, TYPE, URLn--"} $4 !~ /[GCRK_.]/ {print $6, $2, $4, $11, $12, $13 " " $14|"sort -n"}'
Let’s break down this command one by one so you understand what each part does:
Breakdown of Each Part
-
links --dump 1 http://localhost:80/whm-server-status— Fetches the WHM server status page.--dump 1means only grab 1 frame (don’t follow links to other frames). The output is a text table from the Apache server-status page. -
| grep ^[0-9]— Only show lines that start with a number. On the server-status page, lines starting with numbers are active slot lines — each line represents one Apache slot currently processing a request. -
awk 'BEGIN {print "Seconds, PID, State, IP, Domain, TYPE, URLn--"} ...'— The awk section with table header and data processing. TheBEGINpart prints column headers: Seconds (duration), PID (process ID), State (slot status), IP (client address), Domain (virtual host), TYPE (HTTP method), and URL (requested address). -
$4 !~ /[GCRK_.]/— Filter to exclude slots in certain states. The characterG= Graceful shutdown,C= Closing connection,R= Reading request,K= Keepalive,.= empty open slot,_= idle slot. So this command only shows slots that are truly processing requests — stuck, busy, or waiting slots. -
{print $6, $2, $4, $11, $12, $13 " " $14|"sort -n"}— Prints the relevant columns:$6(Seconds/duration),$2(PID),$4(State),$11(Client IP),$12(domain/vhost),$13 $14(type + URL). Results are sorted by duration (sort -n) — slots waiting the longest appear first.
Example Output
Seconds, PID, State, IP, Domain, TYPE, URL
--
2 14233 . 192.168.1.10 clientA.com GET /wp-admin/admin-ajax.php
5 14234 . 192.168.1.20 clientB.com POST /xmlrpc.php
18 14250 . 45.76.100.5 clientC.com GET /wp-login.php
62 14301 . 103.28.12.88 clientD.com GET /wp-cron.php
127 14180 . 178.62.55.200 clientA.com GET /wp-login.php
248 14099 . 89.248.165.12 clientE.com POST /xmlrpc.php
Interpreting the Output
From the output above, we can see several important things:
- First slot (2 seconds) — still normal, request just came in.
- Sixth slot (248 seconds) — this is very suspicious. The request to
/xmlrpc.phphas been running for over 4 minutes. This is likely a brute force attack or XML-RPC pingback abuse. This slot has been consuming server resources for 4 minutes without any progress. - Notice the pattern — almost all stuck requests are hitting
wp-login.php,xmlrpc.php, andwp-cron.php. This indicates your server is being targeted by a brute force attack.
Command #2: Identify the Website Consuming the Most Slots
After finding stuck slots, the next step is to determine which website is consuming the most slots. This is important for prioritizing action — whether to block a specific IP, disable a specific website, or just increase the number of slots.
links --dump http://127.0.0.1/server-status | grep '^[0-9]-[0-9]' | awk '{for(i=1;i<=NF;i++) if($i ~ /^http/1.[0-1]$|^h2$/) {print $(i+1); break}}' | sed 's/:80//;s/:443//' | sort | uniq -c | sort -nr
Let's break down this command too:
Breakdown of Each Part
-
links --dump http://127.0.0.1/server-status— Fetches the server-status page without frames (--dumpwithout a number). We use127.0.0.1because it must be accessed from localhost only (there's usually an IP restriction on Apache). -
| grep '^[0-9]-[0-9]'— Filters lines starting with the pattern number-letter-number (like1- 23,2- 45). These are the detail slot lines containing complete information about one Apache slot, including the virtual host (domain) serving the request. -
awk '{for(i=1;i<=NF;i++) if($i ~ /^http/1.[0-1]$|^h2$/) {print $(i+1); break}}'— Loops through each field in the line and searches for a field matchinghttp/1.0,http/1.1, orh2(HTTP version). Once found, it takes the next field ($(i+1)) — which is the virtual host name or IP port. This is how we determine which domain that slot is serving. -
| sed 's/:80//;s/:443//'— Removes port numbers (:80 or :443) from the domain name for clean output. -
| sort | uniq -c | sort -nr— Sorts, counts occurrences of each domain, then sorts by highest count first.
Example Output
142 clientA.com
67 clientD.com
31 clientB.com
8 clientC.com
5 clientE.com
3 (helicon.nginx)
From this output, it's crystal clear: clientA.com is consuming 142 slots out of 256 total — meaning this single website alone is using more than 55% of all Apache slots. This website needs immediate action.
Command #3: Check Slots in Waiting or Stuck State
Sometimes we need to know which slots are truly stuck — slots that have been waiting extremely long with no progress. This is different from slots processing requests that genuinely take a long time (like generating large reports). Stuck slots usually indicate a problem in PHP execution, database, or external resources.
links --dump 1 http://localhost:80/whm-server-status | grep "W" | awk '{print $2, $6, $12}' | sort -rn | head -20
Or if you want to see slots in any state that have been running for over 30 seconds:
links --dump 1 http://localhost:80/whm-server-status | grep '^[0-9]' | awk '$6 > 30 {print $6, $2, $4, $11, $12, $13, $14}' | sort -rn
Interpretation
Slots running for over 30 seconds without completing can be a warning sign. Several possibilities:
- Slow database query — a request waiting for a query to finish. Can be checked with
SHOW PROCESSLISTin MariaDB/MySQL. - External API timeout — a website calling an external API that isn't responding.
- PHP infinite loop — a script trapped in an endless loop.
- File I/O bottleneck — a website reading large files from a slow disk.
Command #4: Count Total Slots Used vs Available
For an overall picture, here's the command to count how many slots are in use and how many are still available:
links --dump 1 http://localhost:80/whm-server-status | grep '^[0-9]' | wc -l
Or the more detailed version:
links --dump 1 http://localhost:80/whm-server-status | grep 'servers available|servers busy|Total accesses' | head -5
If MaxClients is 256 and you see 256 active slots with only 2 or 3 in idle state (_ or .), then your server is nearing its limit. If all slots are busy (W or .. without idle), then the server has truly run out of slots.
How to Fix Apache Slots Being Full
⚠️ SECURITY WARNING: Backup Configuration Before Making Changes
Before making any Apache configuration changes, you MUST backup the existing configuration files first. A wrong configuration change could prevent Apache from starting at all.
cp /etc/apache2/conf/httpd.conf /etc/apache2/conf/httpd.conf.bak-$(date +%Y%m%d-%H%M)
cp -r /etc/apache2/conf.d/ /etc/apache2/conf.d.bak-$(date +%Y%m%d-%H%M)
IMPORTANT: After backup, verify it succeeded:
ls -lh /etc/apache2/conf/httpd.conf.bak-*
ls -lh /etc/apache2/conf.d.bak-* 2>/dev/null
Never make configuration changes without a backup — because if something goes wrong, you need to restore the correct configuration as quickly as possible.
Solution 1: Optimize KeepAliveTimeout
One of the quickest and most effective changes is reducing KeepAliveTimeout. The default is usually 5-15 seconds. For servers that frequently run out of slots, lower it to 2-3 seconds:
KeepAliveTimeout 3
MaxKeepAliveRequests 100
This change ensures slots aren't locked too long by finished connections. After making the change, restart Apache:
systemctl restart httpd
Verify: Make sure Apache started successfully after the restart:
systemctl status httpd
curl -s -o /dev/null -w "%{http_code}" http://localhost/
Solution 2: Increase MaxClients (If RAM Allows)
If your server has sufficient RAM, you can increase the number of MaxClients. First calculate how many slots can be added:
free -m | head -2
ps -C apache2 -o pid,rss,cmd --no-headers | awk '{sum+=$2; count++} END {print "Average RSS per slot:", sum/count/1024, "MB"; print "Total slots:", count}'
From this output, you can calculate: if the average slot uses 30MB RAM and the server has 2GB free, you can add around 60 more slots. But don't forget to reserve RAM for the operating system and database.
Solution 3: Block Aggressive IPs
If Commands #1 and #2 show a specific IP consuming many slots with suspicious requests (like brute force against xmlrpc.php or wp-login.php), block it immediately:
# First check which IP has the most requests
links --dump 1 http://localhost:80/whm-server-status | grep '^[0-9]' | awk '{print $11}' | sort | uniq -c | sort -rn | head -10
After identifying the IP, add it to CSF firewall or .htaccess:
# Via .htaccess (if CSF isn't available)
# Add at the beginning of the affected website's .htaccess file:
# Order Deny,Allow
# Deny from 103.28.12.88
Solution 4: Disable xmlrpc.php (If Not Needed)
XML-RPC is the primary entry point for brute force attacks on WordPress. If your website doesn't need remote posting or mobile apps that use XML-RPC, just disable it:
# Add to .htaccess or virtual host config:
# <Files xmlrpc.php>
# Require all denied
# </Files>
Solution 5: Add Rate Limiting to Apache
Rate limiting can prevent a single IP from consuming too many slots:
# In .htaccess or virtual host:
# <IfModule mod_evasive20.c>
# DOSHashTableSize 3097
# DOSPageInterval 1
# DOSSiteInterval 1
# DOSPageCount 5
# DOSSiteCount 50
# DOSBlockingPeriod 10
# </IfModule>
Pro Tips: Preventing Apache Slots from Filling Up
- Monitor slots regularly — don't wait for 503 errors. Set up a cron job for alerts:
links --dump 1 http://localhost:80/whm-server-status | grep '^[0-9]' | wc -l | awk '{if ($1 > 200) print "ALERT: Apache slots high - "$1"/256"}' - Optimize PHP execution time — set
max_execution_timein php.ini to 30 seconds. Requests longer than 30 seconds are likely already problematic. - Use opcache — PHP opcache significantly reduces execution time. Make sure opcache is enabled on all websites.
- Set up mod_remoteip — if your server is behind Cloudflare or a load balancer, make sure Apache sees the client's real IP, not the proxy's IP.
- Use a Reverse Proxy (Nginx) in front of Apache — Nginx handles static connections more efficiently and can filter requests before they reach Apache.
- Automated alerts — set up monitoring like Zabbix or even a simple cron to alert via Telegram/Email when slots reach a certain threshold.
- Review logs regularly — check
/var/log/apache2/error_logfor recurring error patterns.
FAQ
What's the ideal MaxClients for a cPanel server?
It depends on RAM and website types. For a 4GB RAM server with lightweight WordPress sites, MaxClients of 150-200 is sufficient. For an 8GB server with heavier websites, it can go up to 300-400. The key is monitoring — see how many slots are normally in use and adjust from there.
What's the difference between 503 Service Unavailable and 502 Bad Gateway?
Error 503 means Apache can't accept new requests because slots are full or the service is down. Error 502 means there's a problem with the upstream — for example PHP-FPM isn't responding or the proxy can't reach the backend. For 503, check Apache slots. For 502, check PHP-FPM and proxy configuration.
How do I know if slots are full due to a DDoS attack?
Check Apache logs for abnormal request patterns: the same IP requesting thousands of times within seconds, requests to weird paths (e.g., /wp-login.php repeatedly), or requests from the same IP range. If the pattern looks suspicious, enable rate limiting and consider using Cloudflare or ModSecurity.
Is it safe to restart Apache in production?
Yes, restarting Apache in production is generally safe as long as you've backed up the configuration first. A normal restart (not a graceful stop) will disconnect all active connections, but clients will automatically reconnect. What to watch out for: make sure there are no deployments or code changes in progress, as the restart could interrupt them.
Related Issues
- How to Troubleshoot High Database Load in MariaDB — often occurs alongside Apache slots being full because requests are waiting for database queries to finish
- How to Detect & Delete Email Spam on cPanel Server via Exim — spam emails can also consume server resources that impact Apache slots
- Why DNS Changes Take Time to Propagate — understanding DNS propagation is important during website migrations that can cause traffic spikes
Conclusion
Apache slots being full is a problem that can strike at any time, but if you know how to read server-status correctly, you can catch it before it's too late. The two core commands you need to memorize are:
links --dump 1 http://localhost:80/whm-server-status|grep ^[0-9]|awk '...'— to view the status of each slot and find stuck requestslinks --dump http://127.0.0.1/server-status | grep ... | awk ... | sort | uniq -c | sort -nr— to find which website is consuming the most slots
With these two commands, you can quickly identify the root cause and take appropriate action — whether that's blocking aggressive IPs, optimizing KeepAliveTimeout, or increasing MaxClients. Most importantly, don't wait for 503 errors to appear in monitoring. Monitor slots regularly, set up automated alerts, and always backup configuration before making changes. Better to prevent than to have to restart Apache at 3 AM while the client is calling — trust me, I've been there and don't want to go through it again.