Quick answer
The official WordPress hosting requirements are PHP 8.3 or greater, MariaDB 10.11+ or MySQL 8.0+, and HTTPS. Every host on the market meets that. What actually decides whether your site stays up is capacity: PHP workers, memory per worker, and database CPU, sized against concurrent uncached requests rather than monthly pageviews.
Search for wordpress hosting requirements and you get the same paragraph from twenty different pages: a PHP version, a MySQL version, a note about HTTPS. All correct, all useless, because no host sold in the last five years fails that list. Meeting the requirements is table stakes. It tells you nothing about whether your site will survive a Black Friday hour or a bot crawling your search results.
There are two questions buried in that one phrase. The first is what WordPress technically needs to boot. That has a short official answer and it gets one section here. The second is how much server your particular site needs, which is the question you actually came with, and which almost nobody answers because the honest answer requires arithmetic.
This post does the arithmetic. It also makes a claim you will not like if you have just been told to upgrade your plan: most WordPress sites that are told they need more server are running a cache that is not working.
What are the official WordPress hosting requirements?
WordPress officially requires PHP 8.3 or greater, MariaDB 10.11+ or MySQL 8.0+, and HTTPS on every install, with Apache or Nginx recommended as the web server. That is the whole list, published on the WordPress.org requirements page, and it has not been a meaningful filter on hosting choice for a long time.
| Component | Official requirement | What WordPress will still run on | What you should actually be on |
|---|---|---|---|
| PHP | 8.3 or greater | 7.4+ | 8.3 or 8.4, ideally with OPcache enabled |
| Database | MariaDB 10.11+ or MySQL 8.0+ | MySQL 5.5.5+ | MySQL 8.0+ or MariaDB 10.11+ on its own CPU allocation |
| HTTPS | Required for every install | Technically boots without it | TLS terminated at the edge, HTTP/2 or HTTP/3 |
| Web server | Apache or Nginx recommended | Anything that speaks PHP | Nginx or LiteSpeed with a page cache in front of PHP |
The PHP version gap most articles skip
WordPress will still run on PHP 7.4, and PHP 7.4 stopped receiving security fixes years ago. Those two facts sit next to each other on the official requirements page, which explicitly warns that the legacy versions have reached end of life and may expose your site to vulnerabilities. Plenty of hosts read the “still runs on” line and stop there.
Check the gap against the source. PHP’s own supported versions page gives each branch two years of active support and two more of security-only fixes. As of the second half of 2026, 8.4 and 8.5 are in active support, 8.3 has moved past its active window, and 8.2 is in security-only maintenance with its end date approaching. Everything older than 8.2 receives nothing from php.net at all.
So the practical floor is not “whatever WordPress boots on”. It is “a branch php.net still patches”. If your host’s control panel still offers 7.4 as the default, that is not a compatibility feature. That is a maintenance signal, and it should weigh on your decision more than the price does. Our comparison of WordPress hosting providers covers who keeps current and who does not.
The PHP settings and extensions that actually break things
Six PHP settings cause the overwhelming majority of “my site is broken” tickets, and none of them appear on the official requirements list. You arrive at these with a symptom, not a setting name, so here they are mapped the way you meet them.
| Setting or extension | Symptom you actually see | Sane value |
|---|---|---|
memory_limit | White screen on a page with many blocks, “Allowed memory size exhausted” in the error log, importers dying midway | 256M for most sites, 512M for WooCommerce and page builders |
max_execution_time | Backups, imports and bulk edits stop partway with no error message | 120s for web requests, higher or unlimited for CLI |
upload_max_filesize | “The uploaded file exceeds the upload_max_filesize directive” on media upload | 64M or more |
post_max_size | Large uploads fail silently even though upload_max_filesize looks fine | Equal to or larger than upload_max_filesize |
max_input_vars | A long menu, a large form or a theme options page silently drops everything past a certain point on save | 3000 minimum, 5000+ for big menus and form plugins |
| curl, mbstring, gd or imagick, zip, intl | Failed updates, broken thumbnails, mangled accented characters, license checks that never connect | All present; see the hosting handbook list |
The Make WordPress hosting handbook is the primary source here. It lists only json and mysqli as strictly required, then names curl, dom, exif, fileinfo, hash, imagick, intl, mbstring, openssl, xml and zip as highly recommended, plus one caching extension from apcu, memcached, opcache or redis. Treat “highly recommended” as required in practice: plugins assume them.
Watch out
max_input_vars fails without an error. A menu with 90 items saves the first 60 and drops the rest, and WordPress reports success. If a large menu, a WooCommerce attribute set or a form builder keeps losing entries on save, this is the cause roughly every time.
Memory is the one setting you can raise from WordPress itself. Add this to wp-config.php above the “That’s all, stop editing” line. The first constant covers front-end requests, the second covers admin and cron, which need more. Both are documented in the wp-config.php API reference.
define( 'WP_MEMORY_LIMIT', '256M' );
define( 'WP_MAX_MEMORY_LIMIT', '512M' );
One caveat: WordPress cannot exceed the PHP memory_limit your host sets. If PHP is capped at 128M, setting 512M in wp-config achieves nothing. Check the real value in Tools then Site Health then Info then Server before you assume the constant worked.
Cached and uncached requests are completely different workloads
A cached page and an uncached page cost your server amounts that differ by two or three orders of magnitude, which is why monthly pageviews are a near-useless sizing input. A cached hit is a file read or a memory read: the web server returns bytes it already has and PHP never wakes up. An uncached request boots PHP, loads WordPress core, initialises every active plugin, runs dozens of database queries, renders a template, then throws it all away.
Two sites with identical traffic graphs can therefore sit at completely different points on the load curve. The only number that sizes a plan is concurrent uncached requests. Everything else is vanity.
What makes a request uncacheable:
- Logged-in users. Any session cookie normally bypasses the page cache entirely, so a membership site can have a 0% hit ratio on its most-visited pages.
- Carts and checkout. Cart contents, shipping calculations and totals are per-visitor by definition.
- Search. Every
?s=query is a fresh full-text database query, which is exactly why crawlers hitting search URLs flatten small servers. - Personalised content: geo-targeted blocks, “recently viewed”, A/B tests, dynamic pricing.
- POST requests. Comments, form submissions, add-to-cart, and admin-ajax calls never come from cache.
- Admin work. Every wp-admin page load is an uncached PHP request, and a bulk product edit is dozens of them.
PHP workers: the arithmetic that actually sizes your plan
A PHP worker is one PHP-FPM process that can handle exactly one request at a time, from first byte of the request to last byte of the response, and your uncached concurrency is simply the number of workers divided by your average uncached response time. Hosts often bury this number, or express it as “you may have up to N concurrent PHP processes”. It is the single most important line on a plan page.
The formula: uncached requests per second = workers / average response time in seconds.
Worked example, stated assumptions, no measurements involved. Take a plan with 4 PHP workers. On a well-tuned blog where an uncached page renders in 250ms, each worker completes 4 requests per second, so 4 workers absorb 16 uncached requests per second. That is comfortable for almost any editorial site, because the cached traffic never touches PHP at all.
Now the same 4 workers on a WooCommerce store where checkout, cart fragments and account pages average 1.5 seconds. Each worker now completes 0.67 requests per second, so the same plan supports about 2.7 uncached requests per second. The pageview count has not changed. The capacity has fallen by a factor of six, purely because the requests got slower and stopped being cacheable.
Six times slower responses means six times less capacity on identical hardware. Response time is a capacity multiplier, not a user-experience nicety.
When demand exceeds that number, requests queue. Queueing is invisible at first: pages just feel slower, because time in the queue is added to every response. Push further and the queue hits its limit, and the web server returns 502 or 504 while your server CPU sits at a modest percentage, which is the detail that confuses everybody. You are not out of CPU. You are out of workers.
This is why a bot crawling /?s= URLs at 5 requests per second can take down a store that handles its human traffic without complaint. Those requests are uncacheable, slow, and database-heavy, and they hold workers hostage while real customers queue behind them.
How much hosting each type of WordPress site actually needs
Sizing follows from the dominant workload, not the traffic total, so the useful way to read this table is to find the row whose workload description matches yours and then look at the constraint column. That constraint is the resource to buy more of. Everything else on the plan page is noise.
| Site profile | Dominant workload | Real constraint | Tier that fits | First thing that breaks |
|---|---|---|---|---|
| Personal blog | Almost entirely cached reads | None, realistically; bandwidth at most | Cheapest shared plan with current PHP | Nothing, until a plugin adds an uncached widget to every page |
| Business or brochure site | Cached reads plus contact form POSTs | Memory per worker (page builders are heavy) | Shared or entry cloud, 256M+ memory | White screen on the page-builder editor |
| Content site with real traffic | High cached volume, spiky | Cache hit ratio and edge bandwidth | Entry cloud plus a CDN | Origin swamped when the cache purges after a publish |
| Membership or LMS | Logged-in, so effectively 100% uncached | PHP workers | Mid cloud, 8+ workers, object cache mandatory | 504s at course-release time while CPU looks idle |
| Small store (under ~50 orders/day) | Mixed; catalogue cached, cart and checkout not | PHP workers and database CPU | Mid cloud with Redis object cache | Checkout timing out during a promotion |
| Busy store | Sustained uncached writes and order queries | Database CPU, then disk I/O | Dedicated database resources or managed WooCommerce tier | Admin order screens crawling while the shop front stays fine |
| Multisite network | Many small sites, many cron jobs, huge table count | Disk I/O and database connections | VPS or dedicated with tuned MySQL | Random slow queries and connection-limit errors at cron o’clock |
Note what is missing from the constraint column: raw CPU cores. Cores matter for the busy-store and multisite rows, and barely anywhere else. If you are being upsold on vCPUs for a membership site, the person selling has not read the workload. Our breakdown of what managed WordPress hosting actually buys you is the place to weigh whether the premium is worth it for your row.
Your database is a more likely culprit than your server size
A WordPress database gets slow in five predictable ways, and all five are free to fix while a bigger plan is not. Every uncached page load pays these costs on every request, which is why database bloat feels exactly like insufficient hardware.
- Autoloaded options. Every option marked for autoload is pulled into memory on every single request. Plugins that store license blobs, cached API responses or entire settings trees here can push the autoload payload into megabytes.
- Post revisions. Unlimited by default. A long-running editorial site can hold more revision rows than real posts.
- Orphaned postmeta. Deleted posts and removed plugins leave meta rows behind, and postmeta is usually the largest table in the database.
- Transients that never expire. Without a persistent object cache, transients land in wp_options, and expired ones are only cleaned opportunistically.
- Plugin log tables. Security scanners, form submissions, redirect logs and analytics plugins write unbounded tables that nobody ever prunes.
Check the autoload payload first, because it has the best ratio of effort to reward. Run this over WP-CLI, adjusting the table prefix if yours is not wp_:
wp db query "SELECT COUNT(*) AS autoloaded_rows,
ROUND(SUM(LENGTH(option_value))/1024/1024, 2) AS autoload_mb
FROM wp_options WHERE autoload NOT IN ('no','off','auto-off');"
# then find the worst offenders
wp db query "SELECT option_name, ROUND(LENGTH(option_value)/1024, 1) AS kb
FROM wp_options WHERE autoload NOT IN ('no','off','auto-off')
ORDER BY LENGTH(option_value) DESC LIMIT 20;"
Anything under roughly 300KB of autoloaded data is unremarkable. Past about 1MB you are paying a real cost on every uncached request, and the second query will usually name one or two plugins responsible for most of it. Flip those options to non-autoloaded or remove the plugin. Neither action costs a hosting upgrade.
Before you upgrade: capacity problem or caching problem?
A capacity problem and a broken cache present identically from the outside, which is why so many people buy hardware they did not need. Both look like a slow site under load. The difference is that one costs money every month and the other is usually a configuration line. Establish which you have before you touch the plan page.
Step 1: compare cached and cache-busted TTFB
Time to first byte on a cached URL against a deliberately cache-busted one tells you where the time goes. Run both from the same machine, several times each:
curl -o /dev/null -s -w "cached ttfb: %{time_starttransfer}s\n" \
https://example.com/
curl -o /dev/null -s -w "busted ttfb: %{time_starttransfer}s\n" \
"https://example.com/?nocache=$(date +%s)"
If the cached figure is small and the busted figure is large, your cache is working and your PHP layer is slow. If the two are similar and both large, your cache is not serving anything and you have a caching problem wearing a capacity costume.
Step 2: confirm a HIT, do not assume one
A caching plugin being active is not evidence that it is returning cached pages. Read the response headers and look for an explicit hit:
curl -sSI https://example.com/ | grep -i -E \
'x-cache|cf-cache-status|x-litespeed-cache|x-proxy-cache|age|cache-control|set-cookie'
A cf-cache-status: DYNAMIC or a missing hit header on a page that should be static means PHP rendered that response. A set-cookie on an anonymous page is worse: it usually means something is stamping a cookie on every visitor, and most cache layers refuse to store a response that sets one. That single line can disable caching for your entire audience, which is the failure mode the Cache Inspector in the WPColt toolbox exists to surface, and it is covered in detail in our writeup on diagnosing Cloudflare cache bypasses.
Step 3: check the object cache is connected
A Redis or Memcached object cache that has silently fallen back to the database is one of the most expensive invisible failures in WordPress, because every uncached request quietly returns to hammering MySQL while the plugin still shows as installed. Tools then Site Health then Info then Database will tell you whether a persistent object cache is in use, and our guide to tracking down Redis object cache misses covers the cases where it reports connected and still is not helping.
If you run a full-page reverse proxy in front of a caching plugin, the two layers can also fight each other and cancel out. Our notes on running Varnish alongside WP Rocket cover the combinations that work and the ones that produce a permanent MISS.
When to actually upgrade, and what to try first
Upgrade when you can name a measurable symptom and point at the specific resource it exhausts, and not before. Each trigger below has a cheaper fix that resolves it more often than the upgrade does.
| Measurable symptom | Resource to increase | Cheaper fix to try first |
|---|---|---|
| 502 or 504 errors while CPU sits low | PHP workers | Cut average uncached response time; block bots hitting search and filter URLs |
| Cached TTFB fine, busted TTFB over 1.5s | CPU clock speed or PHP workers | Enable a persistent object cache; audit autoloaded options |
| Both cached and busted TTFB slow | Nothing yet | Fix the cache; this is not a hardware problem |
| “Allowed memory size exhausted” in logs | Memory per worker | Raise WP_MEMORY_LIMIT; find the plugin loading everything into memory |
| Admin slow, front end fine | Database CPU | Prune revisions, orphaned postmeta and plugin log tables |
| Site fine until you publish, then origin load spikes | Edge cache coverage | Stop full-site cache purges on publish; purge selectively |
| Checkout times out but catalogue is fast | PHP workers plus database CPU | Disable cart fragments where unused; move sessions to the object cache |
| Disk-heavy backups slow the site every night | Disk I/O | Move backups off-peak and off-server |
Mistakes that put people on plans they do not need
Four specific errors account for most over-buying, and each one has a concrete consequence you can check for today.
- Sizing on monthly pageviews. Consequence: you buy a plan rated for 500,000 visits and still get 504s, because your 30,000 logged-in sessions were the entire workload and nobody counted them.
- Treating “caching plugin installed” as “caching working”. Consequence: months of paying for capacity to render pages that should have been served from disk. Verify with headers, not with the plugin dashboard.
- Purging the entire cache on every publish. Consequence: a content site with good hit ratios drops to zero cached pages several times a day, and every purge sends full traffic to PHP. Purge the post, its archives and the homepage instead.
- Leaving WooCommerce cart fragments running site-wide. Consequence: every page on the site fires an uncached admin-ajax request, so even your cached pages generate PHP work. This alone can double worker consumption on a store.
Pro tip
Before you compare plans, write down three numbers: your PHP worker count, your average uncached response time, and your cache hit ratio. If you cannot fill in all three, you are not ready to choose hosting. You are ready to instrument. Several of the quick wins in our list of tips to make your website run faster move the second number more than a plan upgrade would.
The verdict on WordPress hosting requirements
Most WordPress sites are over-hosted and under-cached, and the fix is almost never the plan page. The official requirements are a formality that any current host clears. Capacity is the real question, and capacity is decided by concurrent uncached requests, worker count and response time, in that order.
If you run a blog, a brochure site or a content site, buy the cheapest plan on a PHP branch php.net still patches, put a CDN in front of it, and spend the saved money on nothing at all. Your constraint is cache correctness, not hardware. Upgrading before you have confirmed a cache HIT is buying a solution to a problem you have not diagnosed.
If you run a membership site, an LMS or a store, ignore visit allowances entirely and shop on PHP workers and database resources. Insist on a persistent object cache. Ask a prospective host for the worker count in writing, and if they will not give you a number, that is your answer about how much of your workload they have thought about.
And if you are currently being told to upgrade, spend twenty minutes on the diagnosis section above first. Two curl commands and a look at the autoloaded options table resolve this more often than a credit card does.
Frequently asked questions
What PHP version does WordPress require in 2026?
WordPress.org states PHP 8.3 or greater as the requirement, while noting that WordPress will still run on PHP 7.4 and above. That legacy floor is not safe advice: php.net only maintains branches for four years, so aim for 8.3 or 8.4 at minimum and treat anything older than 8.2 as unpatched.
How many PHP workers does my WordPress site need?
Divide your peak concurrent uncached requests by the number of requests one worker can finish per second, which is one divided by your average uncached response time. A blog rendering in 250ms gets four requests per second per worker. A store averaging 1.5 seconds gets 0.67. Most cached sites need very few workers.
Is shared hosting enough for WordPress?
For a blog, a brochure site or a content site behind a working CDN, yes. Those workloads are almost entirely cached reads, so PHP is barely involved. Shared hosting fails on logged-in workloads: membership sites, learning platforms and stores keep PHP busy on every request and need guaranteed worker counts instead.
Why is my site slow when the server CPU is low?
That pattern almost always means PHP worker exhaustion rather than a CPU shortage. Requests queue while waiting for a free worker, so response times climb and eventually the web server returns 502 or 504 errors, all while the CPU graph looks calm. Reduce uncached response time or increase worker count.
How much memory limit does WordPress need?
256M covers most sites and 512M is sensible for WooCommerce or a page builder. Set WP_MEMORY_LIMIT and WP_MAX_MEMORY_LIMIT in wp-config.php, but remember WordPress cannot exceed the PHP memory_limit your host configures. Check the real value under Tools, Site Health, Info, Server before assuming the constant took effect.
Does WooCommerce need more hosting than a normal WordPress site?
Yes, but not because of traffic. Carts, checkout, account pages and admin order screens cannot be cached, so a store with modest pageviews can generate far more PHP and database work than a blog with ten times the traffic. Size on PHP workers and database CPU, and run a persistent object cache.
Why does my WordPress menu lose items when I save it?
That is the max_input_vars limit truncating the POST request. PHP silently discards form fields past the configured limit and WordPress reports a successful save, so the extra menu items simply vanish. Raise max_input_vars to 3000 or higher. The same limit breaks large form builders and theme option panels.
How do I check whether my page cache is actually working?
Read the response headers rather than trusting the plugin dashboard. Request a public page with curl and look for an explicit hit indicator such as x-cache, cf-cache-status or x-litespeed-cache. A DYNAMIC status, a missing hit header, or a set-cookie on an anonymous page means the response came from PHP.