WordPress performance degradation under normal traffic

A 15-second WordPress site that plugin-disabling could not fix. The bottleneck was 4.2 million orphaned rows in wp_options. Page load went from 12 seconds to 1.8.

5 September 2026  ·  2 min read

SECTOR

Shared hosting provider

SCALE

~150 accounts on a single node

PLATFORM

CloudLinux, LiteSpeed, MySQL 5.7

ENGAGEMENT

Performance investigation

1.8 s

Page load, down from 12 s

12 ms

Options query, down from 3.4 s

4.2 M

Orphaned rows cleared

Environment

Page load and query time before and after the fixPage load fell from 12 seconds to 1.8 seconds and the wp_options query from 3.4 seconds to 12 milliseconds after 4.2 million orphaned autoload transient rows were cleared.Where the 12 seconds actually wentPage loadbefore12 safter1.8 swp_options querybefore3.4 safter12 msThe cause was not PHP, and not the pluginswp_options had grown to 4.2 M rows of orphaned autoload=yes transients left by an abandoned caching plugin.Every page load ran a bulk SELECT across autoloaded options — overwhelming the buffer pool, forcing disk reads on every request.

Scroll the diagram sideways to see all of it →

The bar that matters is the second one: the query, not the page.

The problem

Normal traffic, abnormal load times. A customer reported their WordPress site loading in 12 to 15 seconds despite entirely normal traffic volumes. The hosting provider suspected a plugin, but disabling plugins made no visible difference.

Investigation

The bottleneck was not in PHP. We profiled the request lifecycle and found the cost was MySQL query time. The slow query log showed a single query against the wp_options table taking 3 to 4 seconds on every page load. That table had grown to 4.2 million rows, courtesy of an abandoned transient caching plugin that had never cleaned up its expired entries.

When disabling every plugin changes nothing, the problem has outlived the plugin that caused it.

Root cause

Millions of orphaned autoload rows. wp_options held 4.2 million orphaned autoload=yes transient rows. Every single page load triggered a bulk SELECT across autoloaded options, overwhelming the buffer pool and forcing disk reads on every request. No amount of plugin toggling addresses that, because the rows outlive the plugin that created them.

At a glance

Challenge

12–15 second page loads at normal traffic; disabling plugins changed nothing.

Approach

Profile the full request lifecycle, then read the slow query log rather than guessing.

Result

1.8 s page load, 12 ms options query, with row-count alerting to prevent recurrence.

The fix

Clear the rows, remove the source, alert on the drift. We cleaned the orphaned transients out of wp_options, removed the abandoned plugin and optimized the table to reclaim space, then verified the autoload row count was back in a healthy range. A cron check now alerts on wp_options row count growth so the same drift cannot build up unnoticed.

Outcome

12 seconds to 1.8 seconds. MySQL query time for the options load fell from 3.4 seconds to 12 milliseconds.

More case studies

Hypervisor I/O Stalls

40 VMs returned to stable I/O

Mail Reputation Containment

18 h To confirmed blacklist removal

Hidden DNS Dependency Outage

0 Rollbacks required

Slow WordPress is usually not the plugins

When disabling plugins changes nothing, the answer is in the query log. We profile the whole request path and fix the actual bottleneck.