Horizontal scaling

Why WordPress Breaks at Scale

WordPress at scale is horizontal scaling: object cache, database load, media offload, PHP workers, and cache purge. See when to stay and when to move.

Updated October 2026

What the next server still has to share

Shared object cache

The default cache dies with the request. Every app server needs the same Redis or Memcached.

PHP workers

One uncached request, plugins included, holds one worker. The rest of the traffic waits.

Primary and media

Writes stay on one database. Uploads on one disk are invisible to the other servers.

WordPress at scale

  • ✕Each extra app server still writes to one database primary
  • ✕Uncached requests wait on PHP workers
  • ✕Media and cache purge have to be designed, not assumed

Static or AI-built site

  • ✓HTML is already built before the request
  • ✓No PHP worker or MySQL query on a cacheable hit
  • ✓A publish is a rebuild, not a purge across app servers

WordPress at scale is a horizontal-scaling problem. A larger VPS is vertical scaling: one machine with more RAM and CPU. Horizontal scaling WordPress means a second application server has to share the object cache, the database, the media library, and the CDN purge rules with the first. As of October 2026, an uncached page is still assembled in PHP on the way through MySQL. WordPress scaling gets fragile when those shared layers were never designed, because the extra server then waits on the same primary and the same worker queue.

What another app server actually shares

One server hides the seams. The site feels like a folder of files and a database on the same box. The moment a load balancer sends the next request somewhere else, four agreements have to already exist:

  • Both servers read and write the same object cache.
  • Writes still have a single database primary, and that primary can take the extra concurrency.
  • An upload saved on server A is visible on server B.
  • A publish clears the HTML that the CDN stored, not only the copy on the server that rendered it.

Miss any one of those and “add a server” is a new outage mode, not capacity.

The object cache has to outlive the request

By default, the WordPress object cache is non-persistent. The data sits in memory for that one request, then it is gone.1 Pantheon’s WP Redis plugin, last modified December 2025, states the horizontal-scaling consequence directly: a persistent object cache has to work across multiple instances of the application, and local file caches or APC do not. Turn persistence off and WordPress falls back to its default runtime object cache.2

Platforms that already run this way do not leave the cache on the web server. WordPress VIP provisions a Memcached cluster for each environment and routes object-cache operations there, instead of back to the database, as of its July 2025 docs.3

A Redis process that only the first server can see is a private cache. The second server misses, recomputes, and can disagree with the first after a write. That is not WordPress at scale. It is two sites sharing a domain.

Database load stays on the primary

An uncached request does not stop at PHP. Nexcess, in docs modified September 2026, describes the worker querying the database, waiting, then rendering theme and plugin code into HTML.4 Kinsta’s PHP docs, as of October 2026, draw the same line from the other direction: cached responses do not need a PHP thread, and threads are what you spend when the site has to read or change data in the database.9

Cleaning revisions, autoloaded options, and tables a plugin left behind is real work, and it belongs in a different article. The cleanup steps are in how WordPress database bloat slows a site. Cleanup shrinks what each query touches. It does not give you a second place to commit a write.

Hosts that already run many web containers still treat writes as single-primary. WordPress VIP’s database docs, updated October 1, 2026, say HyperDB sends writes to the master and reads to replicas.5 Automattic’s HyperDB readme describes the same split: write queries connect to master servers, and MySQL itself does the replication.6 More app servers raise the number of concurrent queries aimed at that primary. They do not add a second primary.

Media offload, or half the servers show a broken image

A normal WordPress install stores uploads in wp-content/uploads on that machine. Altis’s multi-server docs are blunt about the result, as of October 2026: files written to one server’s filesystem are not on the others, and they disappear when that server is replaced.7 WP Engine Autoscale, updated September 3, 2026, routes the media library to shared storage instead of a pod’s local disk so every pod sees the same files.8

Until that move is done, horizontal scaling is a coin toss for every image, PDF, and generated thumbnail. The HTML may be right. The file is on the server that did not get the request.

PHP workers cap the uncached path

Plugins and the theme run inside the worker that drew the request. They do not recruit a second worker for the same page view. Nexcess and Kinsta agree on the ceiling, in docs current as of September and October 2026: one WordPress request occupies one PHP worker (Kinsta now calls these PHP threads), and further uncached requests wait when every worker is busy.49 If the page is already in the full-page cache, that request never takes a worker.

This is the distinction hosting invoices blur. More CPU helps a worker finish. It does not raise how many uncached requests can run at once. Worker count does, and only for traffic that misses the cache. A plugin that holds the worker for a slow query holds the slot the next visitor needed.

CDN and cache invalidation

The edge cache is what makes a small worker pool survivable. On WordPress VIP, as of the November 2025 page-cache docs, most anonymous traffic can be served from the edge without hitting a line of PHP. A unique request, or a request with a no-cache header, bypasses that cache and goes to the origin. The platform then needs an explicit purge when the stored HTML is stale.10

Kinsta’s server-caching docs, updated June 3, 2026, cover the pages that never get that shortcut. Checkout and other dynamic HTML are not eligible for the full-page cache. Updating a post or page is supposed to clear the page cache. Images, CSS, and JavaScript on the CDN are a separate clear.11

So the operational job is invalidation, not only hit rate. Publish a post, change a menu, or ship a plugin that alters markup, and every layer that stored the old response has to let go of it. Logged-in sessions, carts, and per-visitor HTML stay on the PHP path no matter how wide the CDN is. If that is most of the site, the CDN is watching.

What still feels slow after the cache is already on — builder markup, third-party scripts, media weight — is a different audit. That checklist is why a WordPress site stays slow after caching. Those fixes do not remove the worker, the primary, or the purge.

What a static or AI-built site takes off the request

A static or AI-built site does the assembly before the visitor arrives. The request is for HTML the CDN already has. That hit does not take a PHP worker, does not open a MySQL connection, and does not ask which app server holds the upload. A publish rebuilds the page and deploys the new file. Invalidation is the new file, not a race to purge every app server and every cache key.

That trade is a poor fit for live inventory and a checkout that has to be personalized on every hit. It fits marketing sites, programmatic landing pages, and location pages that should be the same HTML for every anonymous visitor. How the location pages themselves should be built is covered in static sites versus WordPress for multi-location SEO. This page is the platform decision underneath that choice.

Use the five signals next. WordPress at scale is fine when each one is already true. Move when the uncached path is the product and the shared layers are still a plan.

Decision box

When WordPress at scale is fine

Horizontal scaling WordPress only works when these five layers are shared. This check does not estimate traffic or hosting cost.

  1. 1

    Edge cache

    Anonymous HTML can skip PHP entirely.

  2. 2

    PHP worker

    One uncached request holds one worker.

  3. 3

    Object cache

    Each app server needs the same cache.

  4. 4

    Database primary

    Writes still land in one place.

  5. 5

    Media store

    A file on one disk is invisible to the next server.

Your site, one signal at a time
  • Public pages are cacheable

    Anonymous HTML, not carts, accounts, or a different page for every visitor.

  • Object cache is shared

    Persistent Redis or Memcached that every app server uses. Not a cache that dies with the request, and not a file cache local to one box.

  • Uploads are off one server’s disk

    Shared storage or object storage, so a second app server can see the same media library.

  • The database primary is sized for writes

    Reads can move to replicas. Writes still go to one primary. That primary has to absorb the uncached query load.

  • Someone owns cache purge

    A publish, menu change, or plugin update clears the page cache, and the CDN is a separate clear when assets change.

Notes

Checked October 2026. Prices and visitor thresholds are left out on purpose. Host plans do not agree, and this page does not invent a number for them.

  1. 1.WordPress Developer Reference, class WP_Object_Cache. “By default, the object cache is non-persistent… only for the duration of the request.” As of October 2026. Source
  2. 2.Pantheon Systems, WP Redis. Last modified December 11, 2025. A persistent object cache has to scale across multiple instances; “local file caches or APC are out.” Disabling persistence falls back to WordPress’s default runtime object cache. As of October 2026. Source
  3. 3.WordPress VIP Documentation, Object cache. Last updated July 22, 2025. Each environment gets its own Memcached cluster, and object-cache operations go to that memory instead of the database. Source
  4. 4.Nexcess Documentation, “PHP Workers & WordPress Site Performance.” Published August 12, 2022, modified September 11, 2026. One uncached WordPress request is handled by one PHP worker; further requests queue; that worker queries the database when the page is not cached. Source
  5. 5.WordPress VIP Documentation, Databases. Last updated October 1, 2026. HyperDB sends writes to the master database and reads to replicas. Source
  6. 6.Automattic, HyperDB readme (current master). Accessed October 2026. Write queries connect to master servers. MySQL, not HyperDB, does the replication. Source
  7. 7.Altis Documentation, S3 Storage. Accessed October 2026. A typical WordPress site stores uploads in wp-content/uploads on one machine. On a multi-server setup those files are not shared, and they disappear when that server is replaced. Source
  8. 8.WP Engine Developer Docs, WordPress on Autoscale. Last updated September 3, 2026. Uploads are routed to shared storage rather than a pod’s local disk, so every pod sees the same media library. Source
  9. 9.Kinsta Docs, WordPress hosting PHP. Accessed October 2026. Each PHP thread (Kinsta’s name for what hosts still call a PHP worker) processes one request at a time. If every thread is busy, further requests wait. Cached content does not need a thread; threads are for database reads, writes, and other uncached work. Source
  10. 10.WordPress VIP Documentation, Page cache. Last updated November 19, 2025. The edge cache can serve a full page without running PHP. A unique request or a no-cache header bypasses to the origin, and the platform has a separate purge for cached URLs. Source
  11. 11.Kinsta Docs, Server caching. Last updated June 3, 2026. Full-page cache does not store dynamic pages such as checkout. Updating a post or page is supposed to clear that cache. The CDN cache for images, CSS, and JavaScript is a separate clear. Source

Frequently Asked Questions

What does WordPress at scale actually mean?

It means horizontal scaling: more than one application server sharing an object cache, a database, a media store, and cache purge rules. A larger single server is a different project. As of October 2026, an uncached WordPress request still runs PHP, queries MySQL, and renders plugins and the theme inside one PHP worker.

Does a persistent object cache fix horizontal scaling?

It fixes one layer. WordPress’s default object cache lasts for a single request, so a shared Redis or Memcached instance is what lets every app server reuse the same computed data. It does not remove PHP workers for cache misses, and it does not move uploads or database writes off the request.

When is WordPress at scale fine?

When public pages are anonymous HTML a CDN can cache, the object cache and media library are shared by every app server, the database primary is sized for writes, and someone owns purge rules when content changes. The decision box on this page checks those five signals.

When should you move off WordPress?

When the uncached path is the product. Carts, accounts, per-visitor HTML, and a large set of pages you would rather ship as files all keep PHP workers busy. Adding app servers then queues requests and piles queries onto one database primary.

How is a static or AI-built site different at the same traffic?

The HTML is already built. A request can be a file from the CDN, with no PHP worker and no MySQL query on that hit. Publishing rebuilds the page and deploys it, instead of purging a dynamic origin across app servers. Live inventory and a personalized checkout are a poor fit for that trade.

See the request path without PHP

Get a free visibility audit of your site. Your report lands in your inbox within 1 business day.

Get my free audit