Drupal High CPU Load: Causes, Troubleshooting and Fixes

A practical guide from beginner to advanced for Drupal site owners and developers.

A Drupal site that suddenly becomes slow, throws 502/503 errors, or gets your hosting account suspended almost always has one thing in common: high CPU usage. The good news is that CPU problems in Drupal follow predictable patterns. In this guide you will learn how to find the cause, fix it step by step, and prevent it from coming back.

Why Does Drupal Use So Much CPU?

Drupal is a powerful, flexible CMS, but flexibility has a cost. Every uncached page request can run PHP code, load many database records, and build a complex render tree. When many requests arrive at once, or when a few requests are very heavy, the CPU becomes the bottleneck.

The most common causes are:

  • Bot, crawler and scraper traffic hitting uncached pages
  • Page caching not working or disabled
  • Slow database queries, often from unoptimized Views
  • Stuck or overlapping cron jobs and queue workers
  • Xdebug or development settings left on in production
  • Outdated PHP versions and missing OPcache
  • Heavy custom code, such as loading full entities in loops

Step 1: Find Out Which Process Is Using the CPU

Before changing anything, identify the culprit. Log in to your server and run:

top -c
ps aux --sort=-%cpu | head -15

What you see tells you where to look:

  • php-fpm or apache2: slow PHP code, uncached pages, or heavy traffic
  • mysqld: slow queries, missing indexes, or heavy Views
  • drush or php-cli: cron, queues, or imports stuck
  • java (Solr/Elasticsearch): indexing or heavy search queries

Step 2: Check Your Traffic

The most common cause of a sudden CPU spike is not your code. It is traffic. Check your access logs for the top IP addresses and user agents:

awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20
awk -F'"' '{print $6}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -10

Look for aggressive bots, brute-force attempts on /user/login, and requests with random query strings that bypass the cache.

How to fix it:

  • Put the site behind Cloudflare or another CDN/WAF
  • Add rate limiting with Nginx limit_req or fail2ban
  • Block abusive bots in robots.txt and at the firewall
  • Use modules such as Antibot or Crawler Rate Limit

Step 3: Make Sure Caching Really Works

Caching is the number one defense against high CPU in Drupal. Check it with:

curl -I https://yoursite.com/

Look for the X-Drupal-Cache: HIT and X-Drupal-Dynamic-Cache headers. If you always see MISS, something is breaking your cache.

Beginner checklist (Configuration → Development → Performance):

  • Enable the Internal Page Cache and Internal Dynamic Page Cache modules
  • Turn on CSS and JavaScript aggregation
  • Set a browser and proxy cache maximum age

Common cache killers:

  • A max-age: 0 somewhere in a block, View or render array, which can disable caching for the whole page
  • Custom code that invalidates cache tags on every request
  • Very frequent content saves that clear related caches

Step 4: Optimize the Database

If mysqld is high, enable the slow query log:

SET GLOBAL slow_query_log = 1;
SET GLOBAL long_query_time = 1;

Then analyze it with pt-query-digest or mysqldumpslow. During a spike, SHOW FULL PROCESSLIST; shows what is running right now.

Typical Drupal database problems:

  • Views with unindexed filters, too many relationships, or no caching. Set Views caching to Tag-based or Time-based.
  • Bloated tables such as watchdog, sessions, cache_* and queue. Disable dblog in production and use syslog.
  • Search API with the database backend on a large site. Move to Solr or Elasticsearch/OpenSearch.
  • Small InnoDB buffer pool. Tune innodb_buffer_pool_size to suit your RAM.

A big win is installing Redis or Memcached as the cache backend so cache tables stay out of MySQL entirely.

Step 5: Tune PHP

PHP configuration has a large effect on CPU:

opcache.enable=1
opcache.memory_consumption=256
opcache.max_accelerated_files=20000
opcache.validate_timestamps=0
  • Use a modern PHP version (8.2 or newer)
  • Make sure Xdebug is not loaded in production
  • Set a sensible pm.max_children for PHP-FPM so the server does not thrash
  • Enable the PHP-FPM slow log to find slow scripts

Step 6: Fix Cron and Background Jobs

Drupal’s Automated Cron runs during normal page requests, which can slow visitors down and pile up under load. Instead:

  1. Disable the Automated Cron module
  2. Run cron from the server’s crontab: drush core:cron
  3. Use flock to prevent overlapping runs
  4. Move heavy tasks such as imports, emails and indexing to the Queue API with dedicated workers

Check stuck jobs with:

drush queue:list

Step 7: Profile Your Code (Advanced)

When the server and traffic look healthy but CPU is still high, the problem is probably in code. Use a profiler:

  • Blackfire, Tideways/XHProf or New Relic for production-safe profiling
  • Webprofiler (part of Devel) for local and staging

Common code problems to look for:

  • Loading full entities inside loops instead of using entity queries or loading in bulk
  • Heavy logic in hook_preprocess or hook_entity_load
  • External API calls without caching
  • Missing cache metadata on custom render arrays

Proper cache metadata looks like this:

$build['#cache'] = [
  'tags' => ['node_list'],
  'contexts' => ['user.permissions'],
  'max-age' => Cache::PERMANENT,
];

Step 8: Add a Reverse Proxy and Scale

For high-traffic sites, the biggest single CPU saver is a reverse proxy cache such as Varnish or Nginx FastCGI cache. Anonymous visitors are served directly from the proxy without PHP running at all.

If you have done everything above and still need more capacity:

  • Scale vertically: more CPU and RAM
  • Scale horizontally: several web servers behind a load balancer, a separate database server, and shared file storage
  • Use a CDN for images, CSS and JavaScript
  • Monitor and alert with tools like Netdata, Prometheus/Grafana or New Relic, with an alert when CPU passes 80%

Quick Troubleshooting Checklist

  1. Which process is using the CPU? (top)
  2. Is there a bot or traffic spike? (access logs)
  3. Is the page cache hitting? (X-Drupal-Cache)
  4. Any slow queries? (slow log and processlist)
  5. Is cron or a queue stuck? (drush queue:list)
  6. Is Xdebug off and OPcache on?
  7. Any recent deploy or module update? (git log, drush pm:list)
  8. Any repeating errors? (drush watchdog:show --count=50)

Final Thoughts

High CPU load in Drupal is rarely a mystery. Start by finding the process, check traffic, confirm caching, then move on to the database, PHP, cron and finally your custom code. Only scale up hardware after fixing the basics, because more servers will not cure a site that is not caching properly.

Need help diagnosing a slow Drupal site? Get in touch and we can review your server, caching and code to find the real cause.