← Back to Home

WordPress autoload audit: the autoload='yes' SQL is wrong

WordPressWP-CLIoperations

If you have ever run a WordPress performance check, you almost certainly typed this:

SELECT SUM(LENGTH(option_value)) FROM wp_options WHERE autoload='yes';

Then compared the number against the folklore that autoload should stay under 800KB, decided everything was fine, and closed the tab.

Here is the problem: **since WordPress 6.6, that query is not measuring your site's real load.** It misses rows, and the gap widens the longer a site runs and the more version boundaries it crosses. This is not a misconfiguration on your part. Core changed the semantics of the autoload column back in July 2024, and almost none of the tutorials (or managed-hosting knowledge bases) followed.

On a content site I actually look after, that legacy query returns 222.0 KB across 123 rows. Re-run with a filter that matches what core really loads, the same site reports 261.4 KB across 142 rows. An 18% undercount. That particular site is nowhere near the 800KB warning line, so the undercount is harmless there today. But if your site is near the threshold, an artificially low number is the worst possible outcome: it convinces you there is no problem yet, so you leave it alone.

This piece covers three things: what the correct filter actually is, how to make changes with the official WP-CLI 2.12 commands instead of hand-editing the database, and what the three widely-confused thresholds (150KB / 800KB / 900KB) each actually govern.

⏳ TL;DR

🥇 **The one thing you must change**: replace WHERE autoload='yes' with WHERE autoload IN ('yes','on','auto-on','auto'). That is the only mandatory edit.

👉 Check the Dell U2723QE 4K USB-C monitor on Amazon >>(the practical productivity gear for long sessions reading SQL output and spreadsheets)

🌟 The companion piece: this whole job happens in a terminal, where screen width and color accuracy decide whether you spot the anomalous row at a glance.

👉 Check the BenQ ScreenBar Halo 2 on Amazon >>

💡 **What the three thresholds really are**: 150KB is a per-option core heuristic, 800KB is the Site Health warning line, 900KB is what wp doctor uses. **Three different jobs, and not one of them is a safety limit.**

---



Step 1: What 6.6 Actually Changed

The change came from the Options API update in WordPress 6.6 (see the official dev note). In essence: the `$autoload` parameter of `add_option()` and `update_option()` changed its default from `'yes'` to `null`, and the `autoload` column in the database now stores one of five values:

Value in the columnWhere it comes fromLoaded on every request?
`on`Code explicitly passed `true`Yes, must load
`off`Code explicitly passed `false`No
`auto`Nothing specified; core decides**Yes** (it still loads today)
`auto-on`Core's size heuristic decided "load it"Yes
`auto-off`Core's heuristic decided "don't load it"No

Two things follow from that table:

1. **auto currently counts as loaded.** Core decides this in a function called wp_autoload_values_to_autoload(), and its body is literally the four-element array 'yes', 'on', 'auto-on', 'auto'. Your legacy query matches exactly one of those four.

2. **There is no upgrade routine.** The dev note says so explicitly. A site that has been upgraded across versions therefore carries both yes and auto-on values in the same column. That is exactly why the drift between the old query and reality compounds over time.

One more thing worth knowing: WordPress 7.1.3 shipped on October 6, 2026 as a security release (a stored XSS in the Comments admin screen, a second-order SQL injection in WXR export, and several other fixes). Only the newest version is actively supported. If you are still on 7.1.2 or older, upgrade before you tune performance — doing it in the other order accomplishes nothing.

Step 2: Three Queries That Give You the Real Number

Back up the database first. There is no reason to skip this:

wp db export backup-$(date +%F).sql --allow-root

**Query 1: the real total.** This one is the core of the whole article, because it matches what wp_load_alloptions() actually does:

SELECT COUNT(*) AS rows_n,
       ROUND(SUM(LENGTH(option_value)) / 1024, 1) AS autoload_kb
FROM wp_options
WHERE autoload IN ('yes', 'on', 'auto-on', 'auto');

Query 2: who is fat. Note this includes transients, which is a piece many audits miss entirely:

SELECT option_name, autoload,
       ROUND(LENGTH(option_value) / 1024, 1) AS kb
FROM wp_options
WHERE autoload IN ('yes', 'on', 'auto-on', 'auto')
ORDER BY LENGTH(option_value) DESC
LIMIT 25;

Query 3: the distribution. This one answers "how old is this site, really?":

SELECT autoload, COUNT(*) AS rows_n,
       ROUND(SUM(LENGTH(option_value)) / 1024, 1) AS kb
FROM wp_options
GROUP BY autoload
ORDER BY kb DESC;

If yes dominates Query 3, most of your options were written before 6.6 and have never been updated since. **Those rows will not pick up the new semantics because you upgraded** — only a manual change fixes them. That is why Query 3 matters: it tells you whether Step 3 is worth your time.

Step 3: Use the Official WP-CLI Commands, Not Hand-Written SQL

WP-CLI 2.12 ships two subcommands, `wp option set-autoload` and `wp option get-autoload` (documented here). **Use them. Do not hand-write `UPDATE wp_options SET autoload=...`.** The commands go through the core API and clear the `alloptions` entry in the object cache as a side effect. A raw SQL UPDATE does not, which leaves you with the maddening situation where the database says one thing and the page still behaves like nothing changed.

Check what a given option currently is:

wp option get-autoload rewrite_rules --allow-root

Change it:

wp option set-autoload some_heavy_plugin_option no --allow-root
# Success: Updated autoload value for 'some_heavy_plugin_option' option.

To batch it, feed Query 2's output in. This one skips anything under 1KB so you do not clobber core configuration:

wp db query "SELECT option_name FROM wp_options
  WHERE autoload IN ('yes','on','auto-on','auto')
    AND LENGTH(option_value) > 1024
    AND option_name NOT IN ('rewrite_rules','siteurl','home','blogname')
  LIMIT 20" --skip-column-names | while read -r opt; do
  wp option set-autoload "$opt" no --allow-root
done

Flush the cache afterward, otherwise alloptions still holds the stale set:

wp cache delete alloptions --allow-root

**What to leave alone.** Changing `rewrite_rules` triggers a full permalink rebuild. Turning off autoload for `siteurl` or `home` adds a query to every single request. Theme `theme_mods_*` options are best left autoloading. **If your site already runs an object cache, verify the effect right after this step** — I wrote about the interaction between autoload and object caching in WordPress 7.1 + Redis object cache in production; reading the two together makes the picture clearer.

Step 4: Stop Conflating the Three Thresholds

This is the section I most wanted to write. Nearly every article out there quotes a single "800KB", but core contains three different numbers doing three different jobs:

NumberDefined inWhat it governsCan you change it?
**150,000 bytes**`wp_filter_default_autoload_value_via_option_size()`If a single option exceeds this and code did not explicitly specify, it gets written as `auto-off`Adjustable via the `wp_max_autoloaded_option_size` filter. Core explicitly advises **against** raising it
**800,000 bytes**`WP_Site_Health::get_test_autoloaded_options_size_limit`The point at which Site Health shows "Autoloaded options could affect performance"Adjustable via the `site_status_autoloaded_options_size_limit` filter
**900 KB**`wp doctor`'s `autoload-options-size` checkThe warning line used by the `wp doctor` commandNot configurable

Two facts you need to internalize:

One more trap, this one in WP-CLI itself: wp option list --autoload=on --format=total_bytes looks like it should do this job, and it **also undercounts** — it matches only on and yes, skipping every auto and auto-on row. Use the SQL above for auditing, not this command.

Troubleshooting: Three Errors I Actually Hit

Error 1: `Error: YIKES! It looks like you're running this as root.`

The full message continues with You probably meant to run this as the user that your WordPress install exists under.

Cause: WP-CLI detected that the current user is root and refused to continue. This is a safety mechanism — running as root means any plugin code on the site has unrestricted control over your server.

Fix (the second option is what I actually use):

# Option 1: bypass once
wp option get-autoload rewrite_rules --allow-root

# Option 2: run as the site's owning user
sudo -u www-data wp option get-autoload rewrite_rules

If you keep hitting this inside containers, set WP_CLI_ALLOW_ROOT=1 once. But understand the residue Option 1 leaves behind: **after running a write operation as root, file ownership becomes root**, and the web server may no longer be able to write. Fix it with chown -R www-data:www-data /var/www/html/.

Error 2: `Warning: Could not delete 'option_three' option. Does it exist?`

**Cause:** The option name was mistyped, or the option was already at autoload='off' and your cleanup script only scanned autoloaded rows so it never matched in the first place. This specific warning text comes from wp option delete, but seeing it mid-cleanup usually means your upstream option_name list is dirty.

Fix: add an existence check so the script stops skipping rows silently:

if wp option get-autoload "$opt" >/dev/null 2>&1; then
  wp option set-autoload "$opt" no --allow-root
else
  echo "SKIP (not found): $opt" >&2
fi

Error 3: The audit script runs clean, but the number disagrees with the admin

This one produces no error output at all, which is why it is the hardest. The symptom: Site Health clearly reports "Autoloaded options could affect performance" while your own SQL comes back with a few hundred KB.

**Cause:** Nine times out of ten you ran autoload='yes'. The other case is missing transients — a transient with no expiry set is autoloaded permanently, and wp option list hides transients by default, so both tools make them vanish from the numbers.

**Fix:** start with Query 3. If auto plus auto-on account for a meaningful share, it is the first cause. If auto-off contains suspicious multi-KB blobs, it is the second. Add a transient-specific query:

SELECT option_name,
       ROUND(LENGTH(option_value) / 1024, 1) AS kb,
       autoload
FROM wp_options
WHERE option_name LIKE '%_transient_%'
  AND LENGTH(option_value) > 512
ORDER BY LENGTH(option_value) DESC
LIMIT 20;

Applying This as a Process, Not a One-Off

Fixing one site by hand is labor. Running multiple sites has to be a process. I put this in three places.

**Pre-launch gate.** Before any new site or new plugin combination ships, run Query 1 and Query 2 as acceptance checks. And do not write the pass criterion as "under 800KB." Write it as "total auto-off volume under 100KB with no single option over 150KB" — the first number is core's advisory line, the second is the actual structure.

Diff checks in CI. WordPress performance regressions are almost never single-event. They arrive quietly with a plugin update. In CI:

NEW=$(wp db query "SELECT ROUND(SUM(LENGTH(option_value))/1024,1) FROM wp_options
      WHERE autoload IN ('yes','on','auto-on','auto')" --skip-column-names)
if (( $(echo "$NEW > $BASE + 50" | bc -l) )); then
  echo "autoload grew more than 50KB, please explain" >&2; exit 1
fi

Monthly scheduled audit. Run Query 1 from cron and send the number plus the top 5 from Query 2 to whoever is on call. This beats waiting for Site Health, because it gives you the trend well before 800KB.

And for perspective on what this is worth: on budget shared hosting, where WordPress plans commonly start around $3.99/mo on a 36-month prepay and managed WordPress runs $10–$60/mo, autoload bloat eats into a per-request cost you are already paying for. I would not spend $50 on a bigger plan to fix a query shape I could correct with three lines of SQL.

One closing caveat: database slimming has a ceiling. Trimming options addresses "every request reads an extra lump of configuration." It does not fix slow queries. If your site is slow because of queries rather than memory pressure, that is a different article — I covered that side in WordPress database optimization in practice, where cutting query time from 3.2 seconds to 180 milliseconds is the whole story. For bulk metadata and internal-link work, see rebuilding internal links across 600 posts with WP-CLI.

Wrapping Up

Back to that opening query. There are really only two takeaways, both small.

**The filter** changes from autoload='yes' to autoload IN ('yes','on','auto-on','auto'). This one is mandatory.

The mental model changes from "800KB is the safe limit" to "800KB is only a warning line, 150KB and 900KB each govern something else, and none of the three is safe." Leave this one un-updated and you will keep making decisions against a threshold that does not exist.

For the hands-on part, prefer wp option set-autoload over hand-written UPDATE statements. It costs two extra seconds of typing and saves an entire category of "I changed it and nothing happened" debugging.

If your site's autoload total is already comfortably low, this article will not make it faster. What it gives you is a number you can finally trust. To confirm the thresholds and function behavior for your specific version, check the official pages: Site Health's autoloaded options test and wp_autoload_values_to_autoload().

Q: Will upgrading to the latest WordPress shrink my autoload automatically?

A: No. The 6.6 dev note states plainly that no upgrade routine is planned. Upgrading only causes newly written options to use the auto-* values. Historical rows are yours to change.

**Q: Is there a difference between auto and auto-on?**

A: Yes. auto means "no decision was made," while auto-on means core's heuristic decided to load it. Under 7.1 both load, but the 6.6 dev note warns that the default behavior for auto **may change in a future release**. If you depend on an option loading via auto, set it to on explicitly.

Q: Do I need the Performance Lab plugin?

A: Its value is that it adds a detailed table to the Site Health check, letting you switch off autoload for an individual option from the admin without touching SQL. If you only audit from the command line, it is not required.

Q: Where does 800KB come from? I've seen articles saying 1MB, others saying 400KB.

A: The 400KB and 1MB figures are pre-6.6 folklore. 6.6 introduced the Site Health check with an 800,000-byte default, while WP-CLI's wp doctor uses 900KB separately. Verify against your own version with grep -rn 'site_status_autoloaded_options_size_limit' wp-admin/includes/class-wp-site-health.php.

👉 Join MiniMax Token Plan: AI coding acceleration for businesses

👉 Join Xiaomi MiMo Platform: Leading AI model platform with cost-effective inference

👉 Join Aliyun AI: Top AI products with exclusive coupons for business innovation

📌 This article was AI-assisted generated and human-reviewed | TechPassive — An AI-driven content testing site focused on real tool reviews

🔗 Recommended Tools

These are carefully selected tools. Using our affiliate links supports us to keep producing quality content:

☁️ DigitalOcean Cloud ⚡ Vultr VPS ⭐ MiniMax Token Plan 🤖 QoderWork CN (Refer & Earn) ☁️ Aliyun AI Products 📚 WordPress Books 🔍 WordPress SEO Books 🌐 Web Hosting Books 🐳 Docker Books 🐧 Linux Books 🐍 Python Books 💰 Affiliate Marketing 💵 Passive Income Books 🖥️ Server Books ☁️ Cloud Computing Books 🚀 DevOps Books 🤖 Xiaomi MiMo Platform
← Back to Home