How many concurrent users can a VPS handle? Do the maths

It all starts with one question: what are those users doing? A thousand people logged into an app do not make a thousand requests per second, and a page served from cache costs a hundred times less than a page built on every visit. This guide turns users into requests, requests into CPU and memory, then shows how to check it all with a load test.

Published on 26 October 2026 By 9 minute read

All guides

In short

  1. Logged-in users are not concurrent requests: an active user sends a request roughly every 10 to 30 seconds.
  2. Requests in flight = requests per second × time per request (Little’s law). That is the number your server has to hold.
  3. One vCPU serves at most 1,000 ÷ (milliseconds of CPU per request) requests per second: 20 ms of CPU, 50 requests per second.
  4. Memory caps the number of workers: each PHP or Python process holds 40 to 200 MB.
  5. Caching changes everything: a cached page costs under a millisecond, an uncached WordPress page 100 to 300.
  6. Measure with a load test (k6, wrk) on a copy of the app, ramping up in steps.

From users to requests

"Concurrent users" means three different things depending on who is talking:

You get from one to the other with Little’s law: the number of requests in flight equals the throughput, in requests per second, multiplied by the average time a request takes.

Worked example. 600 users active at once, each triggering a request every 20 seconds, make 30 requests per second. If each request takes 100 ms, the server has only 3 requests in flight on average. The real challenge lies elsewhere: in peaks and in slow requests.

What one vCPU can serve

A request holds the CPU for as long as it computes: running the code, querying the database, building the response. One vCPU therefore handles at most 1,000 ÷ t requests per second, where t is the CPU time of a request in milliseconds. Time spent waiting (on an external API, on disk) does not use the CPU, but it does tie up a worker.

Type of requestTypical CPU timePer vCPU, order of magnitude
Static file, or page served from cacheUnder 1 msSeveral thousand requests per second
WordPress page served by a page cache1 to 5 msSeveral hundred per second
JSON API (Node.js, Go, FastAPI) with an indexed SQL query5 to 20 ms50 to 200 per second
WordPress or Laravel page built on every visit100 to 300 ms3 to 10 per second
Report, export, PDF generation500 ms to several secondsFewer than 2 per second

With these figures, 30 API requests per second at 10 ms of CPU use 30% of a single vCPU. The same 30 requests per second on uncached WordPress pages need 3 to 9 vCPUs. A page cache exists precisely to move a page from the fourth row of this table to the second.

What memory can hold

Every request in flight is handled by a worker, and workers take memory whether they are busy or not. It is often memory, more than CPU, that caps how many requests the server handles in parallel:

Persistent connections (websockets, real-time notifications) count separately: they stay open, use little CPU and a few tens of kilobytes of memory each. A Node.js server holds thousands of them in a few hundred MB.

The real bottlenecks

In a real application, the server rarely saturates where you expect. The most common causes, in the order to check them:

  1. A slow SQL query: a missing index turns a 2 ms query into a 2 second one that ties up a worker and a connection. pg_stat_statements on PostgreSQL, or the MySQL slow query log, points to it.
  2. Cascading queries (the N+1 problem): a page that runs one query per row it displays runs hundreds of them.
  3. A synchronous external call: a payment or AI API that answers in 3 seconds blocks a synchronous worker for 3 seconds.
  4. Heavy work inside the request: sending email, resizing images, generating PDFs, all better moved to a job queue.
  5. No caching: pages that are identical for every visitor belong in a cache, static files with the web server.

Checking it: the load test

Orders of magnitude give you a first size; a load test gives you the real one. The idea: simulate more and more users on a copy of the application, and note the point where response times break away.

Terminal: 50 connections for 30 seconds, with wrk
wrk -t2 -c50 -d30s --latency https://staging.your-site.com/

For a full user journey (log in, browse, search), k6 describes a scenario in JavaScript and ramps the load up in stages:

k6 script (test.js), run with: k6 run test.js
import http from 'k6/http';
import { sleep } from 'k6';

export const options = {
  stages: [
    { duration: '2m', target: 100 },
    { duration: '5m', target: 100 },
    { duration: '2m', target: 300 },
    { duration: '5m', target: 300 },
    { duration: '2m', target: 0 },
  ],
  thresholds: { http_req_duration: ['p(95)<500'] },
};

export default function () {
  http.get('https://staging.your-site.com/');
  sleep(15);
}

When load grows

The order that costs least and pays back most:

  1. Cache what can be cached (pages, fragments, query results) and fix slow queries.
  2. Tune the number of workers to the memory and CPU available.
  3. Move up to a larger size: more vCPUs and memory, with no change to the application.
  4. Put the database on its own server.
  5. Spread the application across several servers behind a load balancer.

The first three steps cover the vast majority of business applications, websites and APIs: several hundred users active at the same time fit on a single well-tuned server.

A server that grows with your users

VPS Pro comes in six sizes, on Intel Xeon processors, ECC memory and mirrored NVMe SSDs, and moves up to a larger size at any time without reinstalling. Full-Stack Assistance is included: tell us how many users you expect at launch and a year from now and we recommend the size; and when a page slows down, we diagnose it and tell you what to do, from the operating system down to your application code.

Explore VPS Pro

Frequently asked questions

How many users can a VPS with 2 vCPUs and 4 GB handle?

For an API or an app whose requests take 10 to 20 ms of CPU, several hundred users active at the same time. For a WordPress site without a page cache, around a hundred. The gap comes from the CPU time of each request and from caching, which is why a load test is worth running.

How many visitors per day can a VPS take?

Daily visitors say little on their own: what counts is the peak. To convert one into the other, divide the day’s visits by the active hours, multiply by pages per visit, then by a peak factor of 3 to 5. 10,000 visits over 10 hours at 4 pages each give about 1 page per second on average, and 3 to 5 at peak.

How do I know my server is saturated?

Three signs: response time rises with traffic, CPU stays above 80% at busy times, or available memory drops close to zero. The web server logs then show 502 or 504 errors, and requests queue up waiting for a free worker.

Do websockets change the maths?

Yes: a websocket connection stays open all the time. It uses little CPU and a few tens of kilobytes of memory. A Node.js server holds thousands of them; it is the messages sent, more than the open connections, that load the CPU.

Contact us