Do You Actually Need a VPS? Run This Measurement Instead of Guessing
Every article about outgrowing shared hosting gives you a number. “Move to a VPS at 50,000 visits.” “Shared is fine to 10,000 sessions a month.”
Those numbers are not derived from anything. Hosts publish their resource caps — entry processes, memory, CPU — and no host publishes a conversion from those caps to visitors, because the conversion depends on your page weight, your caching, and how long each request holds a slot. No vendor can know those things about your site.
So the honest answer to “do I need a VPS?” is a measurement procedure, not a threshold. Here it is.
The limits you are actually up against
Most cPanel-based shared hosting runs on CloudLinux, whose LVE (Lightweight Virtual Environment) enforces seven per-account limits:
| Limit | What it controls | Documented default |
|---|---|---|
SPEED | CPU, as a percentage of one core | 100% |
PMEM | Physical memory | 1024 MB |
VMEM | Virtual memory | — |
IO | Disk throughput | 1024 KB/s |
IOPS | Disk operations per second | — |
NPROC | Maximum processes | 100 |
EP | Entry processes | 20 |
Server-wide, cPanel adds a second layer through PHP-FPM’s pm.max_children, which “sets the limit on the number of simultaneous requests that will be served.” And there is a third ceiling that almost nobody knows about, documented by cPanel itself: if the combined max_children values across all domains on a server exceed Apache’s Max Request Workers, then Apache — not your site — becomes the bottleneck. You are sharing a budget you cannot see.
Entry processes are not visitors
This is the most common error in this whole topic, and it produces wildly wrong conclusions.
EP is documented as the limit on “concurrent connections to apache dynamic scripts as well as SSH and cron jobs running simultaneously.” An entry process is not a visitor. It is a request in flight, held for milliseconds while PHP builds the page and released immediately after.
Two practical consequences:
A page view is one entry process, but it is released so fast that 20 entry processes can serve far more than 20 visitors per second. Conversely, one heavy uncached page that takes 400 ms to build holds a slot eight times longer than a fast one — so page speed converts directly into concurrency headroom. The cheapest way to raise your visitor ceiling is often to make pages render faster, not to buy a bigger plan.
And a cron job that runs every minute consumes entry processes. If your site gets suspended at a traffic level that seems far too low, a chatty cron schedule is a plausible cause.
The error code tells you which limit you hit
You do not need a dashboard to diagnose this. The symptom identifies the exhausted resource:
| What you see | Likely limit |
|---|---|
| HTTP 508 “Resource Limit Is Reached” | Entry processes |
| Site slow, no error | CPU (SPEED) or disk I/O |
| HTTP 500 / 503 | Memory (PMEM) or NPROC |
The 508 comes from Apache’s mod_hostinglimits, which is documented as returning that code when it “will not be able to place Apache process into LVE.”
Two caveats before you treat that table as universal. CloudLinux documents 508 for entry processes and 500/503 for memory and process limits, but several host knowledge bases describe entry-process exhaustion as a 503 instead. If your host’s own documentation says something different, believe your host. And a 500 is also just a PHP fatal error, so confirm before you blame the plan.
Measuring from inside a shared plan
You have less visibility than a VPS, but you have more than nothing:
# Count throttling events per day for your account
lveinfo --period=1d --by-fault=mep --display-username
# Live view of usage against your limits
lvetop
# Find the process ceiling your plan sets
lvectl list
If lveinfo is not available (common on lower tiers), the fallback is the raw access log: grep for 508 responses and count them per day. That number is your answer. A handful per month is noise. A daily pattern concentrated in your peak hour means you are hitting the ceiling regularly and the platform is protecting itself from you.
On the PHP-FPM side, the diagnostic is the FPM error log and the string max_children, which cPanel’s official guidance names as the way to confirm the limit was reached. cPanel also documents that when pm.max_children is hit, “only a single domain will become unavailable” — the blast radius is smaller than a server-wide outage, which is cold comfort if it is your domain.
The formula vendors won’t publish
The community rule for sizing PHP workers is pm.max_children = available RAM ÷ average worker size. I looked for a primary source for this and could not find one — not in the PHP manual, not in cPanel’s documentation, not in CloudLinux’s. It is a convention, not a citation.
That does not make it wrong. It makes it a derivation you should show your work for:
- Measure the actual resident memory of one worker under load (
pson your own process, or the FPM status page). - Take the memory your plan guarantees — not the number on the marketing page, but
PMEMfrom the LVE table. Note that CloudLinux’sPMEMdefinition includes shared memory and disk cache, so a sales page’s “1 GB” means something narrower than it reads. - Divide, then leave headroom. cPanel’s official remediation is to raise
max_children“in increments of 5” while watching the server — an operational ritual rather than a model, which tells you how much precision the vendors themselves think is available.
If you are on shared hosting, you control none of these numbers directly. Which is the point: you are measuring to decide whether to leave, not to tune.
The ceiling that is set by someone else
MySQL documents max_connections as the control on permitted connections, the “Too many connections” error, and one detail that feels like a bug and isn’t: mysqld actually permits max_connections + 1, with one reserved for a client holding CONNECTION_ADMIN.
On shared hosting, the value is invisible to you. You observe the symptom — your application reporting that it cannot connect — while the knob that governs you belongs to the host. This is the single most frustrating thing about diagnosing a shared plan: the limit you can read and the limit that governs you are different limits.
For context on how tightly some hosts set it: one large provider publishes plan-level allowances including 30 concurrent MySQL connections and 500 SMTP relays per hour. Those are the kinds of numbers that decide whether a traffic spike is an incident.
When a VPS is genuinely the answer
- You are hitting entry-process or CPU limits at your normal peak, not only on a viral day.
- You need software the shared plan does not permit — a specific PHP extension, a daemon, a non-standard database.
- You need to control the MySQL ceiling, because your workload is genuinely connection-heavy.
- Your site is not PHP. A static site or a Node application on cPanel hosting is fighting the platform.
When it is not
If the reason is speed, a VPS rarely fixes it — an unmanaged VPS with the same unoptimised stack is often slower than a competent shared host, because the tuning you were relying on is now your job.
If the reason is one bad day — a front-page spike, a campaign — you are buying a permanent operational burden for a temporary problem. A CDN, page caching, and a queue for anything expensive will absorb it.
And if you would not enjoy being the person who patches the server, the correct upgrade from shared hosting is managed hosting, not a VPS. The distinction is not price; it is who gets paged.
The decision rule, in one paragraph
Measure your actual 508 and 500 counts over a normal month. If they are concentrated in your peak hour and your pages are already cached and fast, you have outgrown the plan. If your pages are not cached and fast, fix that first — it is cheaper, it raises the ceiling you already have, and the measurement you take afterwards will be the one worth acting on.
Written by TestedHost. Every recommendation on this site comes from running the setup described, on a live deployment — not from a vendor spec sheet. Spotted something out of date? Tell us.