Database
Autoloaded options: the tax on every request.
There is a query WordPress runs on every request, before it knows what page you asked for, and on a lot of older sites it is reading several megabytes. Nothing in the admin shows it to you, and almost nobody looks.
What autoloading is
WordPress stores settings in the wp_options table. Each row has an
autoload column, which is either yes or no.
On every request, before routing, before deciding what page you want, WordPress runs roughly this:
SELECT option_name, option_value
FROM wp_options
WHERE autoload = 'yes';
It loads all of them into memory at once, as a single cached blob, so that any later call to
get_option() is free rather than another trip to the database. For the handful of settings
WordPress genuinely needs on every page — the site URL, the active theme, the list of active
plugins — this is exactly right.
The flaw is in the incentive. Autoloading is the default when a plugin calls
add_option() without saying otherwise. So a plugin author who does not think about it gets
autoload for free, and the cost lands on every page view of every site that installs it, forever.
Why it grows
Four things, compounding:
- The default.
add_option()autoloads unless told not to. Most plugin authors never pass the argument. - Uninstall is optional. WordPress gives plugins a clean uninstall hook. Using it is voluntary, and a plugin deleted through the admin frequently leaves its rows behind.
- Some plugins autoload things that should never be autoloaded. Cached API responses. Licence check results. Serialised arrays of every product in a shop. Log data. These get read on every request including ones that could not possibly need them.
- Nothing ever cleans it up. There is no garbage collection for the options table. It only grows.
Five years, thirty plugins installed and removed, and a site can be carrying several megabytes of settings belonging to software it no longer has.
How to measure yours
If you have database access, this is the number:
SELECT ROUND(SUM(LENGTH(option_value))/1024/1024, 2) AS mb,
COUNT(*) AS rows_autoloaded
FROM wp_options
WHERE autoload = 'yes';
And this is the list of what is responsible:
SELECT option_name,
ROUND(LENGTH(option_value)/1024, 1) AS kb
FROM wp_options
WHERE autoload = 'yes'
ORDER BY LENGTH(option_value) DESC
LIMIT 25;
If you use WP-CLI:
wp option list --autoload=on --format=table \
--fields=option_name,size_bytes --orderby=size_bytes --order=desc | head -25
Guru Site Health reports the same figure on its dashboard, if you would rather not open phpMyAdmin.
Under 800KB is healthy. Around 1MB is worth a look. Over 3MB is a real cost on every request, and over 10MB — which happens — is likely to be causing visible slowness and occasional memory errors. These are rules of thumb, not thresholds: the shape matters more than the total, and one 4MB row is a much more interesting finding than four thousand small ones.
Reading the list
Sort by size and look at the top twenty-five. You are looking for four patterns:
Rows belonging to plugins you no longer have
The clearest win. Cross-reference the prefixes against your plugin list. An option named
wpseo_* on a site with no Yoast installed is leftover. Confirm the plugin is really gone —
not just deactivated — before touching anything.
Transients that should not be autoloaded
Rows named _transient_* or _site_transient_*. Transients with an
expiry are not autoloaded by WordPress; ones written without an expiry are. A pile of large autoloaded
transients usually means a plugin is using the transient API as permanent storage.
Single enormous rows
One option of 2MB is worse than two thousand options of 1KB, and much easier to deal with. It is usually a serialised cache, a log, or a settings array that has been accumulating entries.
Thousands of tiny rows with the same prefix
A plugin writing one option per item — per user, per product, per form submission. The total may be modest but the row count makes every query against the table slower.
What is safe to change
This is where people break things, so, carefully:
- Back up the database first. Not negotiable.
wp_optionsholds your site’s configuration, and a mistake here is not a cosmetic one. - Prefer turning autoload off over deleting. Setting
autoloadtonotakes a row out of the every-request query while leaving the data exactly where it is. If something did still need it, it still works — just one query slower. This is almost always the right first move. - Only delete rows whose plugin is definitively gone. Deleted, not deactivated. And search the option name on the web first; some unpromising names belong to core.
- Clear expired transients separately. Safe by definition, since they have already expired.
- Never bulk-delete by pattern.
DELETE ... WHERE option_name LIKE '%cache%'will eventually match something that was not a cache.
Turning autoload off for a row:
UPDATE wp_options SET autoload = 'no'
WHERE option_name = 'the_exact_option_name';
Then clear your object cache if you run one, because the autoloaded set is itself cached.
Switching autoload off is reversible. Deleting is not. When you are not sure, switch it off, use the site for a week, and only then consider deleting.
What changed in WordPress 6.6
WordPress 6.6 began handling this itself, to a degree. Options larger than a threshold are no longer autoloaded by default when added, and core gained functions for setting autoload behaviour explicitly. This helps new sites considerably.
It does not retroactively fix an existing site. Rows already marked yes stay that way.
If your site has been running for years, the accumulated weight is still there and still being read on
every request.
What to expect from fixing it
Honestly: usually tens of milliseconds per request, sometimes a few hundred, occasionally dramatic. It is not the kind of change that turns a three-second page into a one-second page on its own.
What makes it worth doing is that it is a fixed cost on every request — cached pages, admin pages, AJAX calls, cron runs, REST requests. It is one of the few optimisations that helps the admin area as much as the front end, which page caching never does. And on a site carrying 8MB of dead settings, it is also 8MB in every backup you take and every migration you run.
Frequently asked questions
What is a good autoload size for WordPress?
Under 800KB is healthy, around 1MB is worth investigating, and over 3MB is a genuine cost on every request. Sites carrying 10MB or more usually show visible slowness and occasional memory errors. The shape matters as much as the total — one 4MB row is a different problem from four thousand small ones.
How do I check my autoloaded options size?
Run SELECT ROUND(SUM(LENGTH(option_value))/1024/1024, 2) FROM wp_options WHERE autoload = 'yes'; in phpMyAdmin or your database tool. With WP-CLI, use wp option list --autoload=on. Guru Site Health reports the same figure on its dashboard without database access.
Is it safe to delete autoloaded options?
Deleting is not reversible, so prefer setting autoload to no instead. That takes the row out of the every-request query while leaving the data intact, so if something did still need it, it keeps working. Only delete rows belonging to a plugin that has been fully deleted, and back up first.
Why do deleted plugins leave options behind?
Because cleaning up is voluntary. WordPress provides an uninstall hook, but using it is the plugin author’s choice, and many do not — sometimes deliberately, so settings survive a reinstall. There is no garbage collection for the options table, so leftover rows stay forever.
Did WordPress 6.6 fix the autoload problem?
Partly, and only going forward. Core now avoids autoloading unusually large options by default and added functions for controlling it explicitly. Rows already marked to autoload on an existing site are unaffected, so an older site still carries everything it accumulated before the change.
Does reducing autoload size actually make my site faster?
Usually by tens of milliseconds per request, occasionally much more. It will not single-handedly fix a slow site. What makes it worthwhile is that it is a fixed cost on every request including admin pages, AJAX and cron — places page caching never helps — and that the dead weight is also in every backup and migration you run.
Find these on your own site in about ten seconds
Guru Site Health runs 32 checks across updates, security, database, media, accessibility and SEO, and gives you one score. Thirteen of the findings can be fixed from the dashboard in one click, and every fix can be undone. It makes no external requests — nothing about your site ever leaves it.