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.