← Back to Blog

How to Test a VPS Before You Trust It: 6 Benchmark Commands With Real Numbers

Published · by RS Computers

Benchmark Linux VPS

The quickest honest VPS benchmark test is six commands run on the server itself in the first hour after you get it: sysbench for CPU and memory, fio for disk, iperf3 or a large file download for bandwidth, ping and mtr for latency and routing, and vmstat for CPU steal time, the one number that shows whether the host is oversold. This guide shows how to benchmark a VPS with each tool, explains the flags, and gives the exact numbers we measured on our own Amsterdam server on 9 October 2026, so you have something real to compare against.

Key facts, checked on 9 October 2026:

The checklist and our results at a glance

We ran every command in this article on an RS Computers server in Amsterdam: a KVM virtual machine with 8 shared vCPUs (AMD EPYC 7742), 16 GB of RAM and NVMe storage, the same size as our VDS Medium plan, running Debian 13. The tools ran in a fresh Debian 13 container on that server with all 8 cores. A container shares the server's kernel, CPU and disk, so the CPU, steal and disk figures are the server's own; network traffic passed through the container's NAT, which, if anything, lowers those numbers. Nothing else was running on the server at the time.

CheckToolOur Amsterdam resultHealthy signRed flag
1. CPUsysbench cpu597 events/s on 1 thread, 4,763 on 8 threads (7.98 times)All threads score close to N times one thread8 threads score far less than 8 times one thread
2. Memorysysbench memory19,641 MiB/s write and 43,267 MiB/s read on 1 threadTens of GB/s on current server CPUsA small fraction of that, or the test swaps
3. Diskfio62,200 read and 53,300 write IOPS at 4k; 0.11 ms median single readTens of thousands of 4k IOPS, sub-millisecond single requestsA few thousand IOPS or several ms per request on "NVMe"
4. Bandwidthiperf3, curl4.9 to 6.5 Gbit/s to Amsterdam test servers, 3.2 Gbit/s to LondonClose to the port speed with parallel streamsFar below the port speed to every server you try
5. Latencyping, mtr0.5 ms to 8.8.8.8, 6.1 ms to London, 6.7 ms to Frankfurt, 0% lossLow, stable times and 0% loss at the destinationLoss that continues all the way to the last hop
6. Stealvmstat, mpstat, top0% on all 8 vCPUs at 100% load0 to 1% most of the timeAbove 5% for long stretches

One run is a single reading, not a verdict. Shared vCPUs and shared links behave differently at 03:00 and at 20:00, so repeat the checks at different hours before you judge any server, ours included.

Before you start: look at the machine and install the tools

First confirm you got what you paid for. These commands read information only and change nothing:

# as a normal user (we used one called bench)
nproc
lscpu | grep -E "Model name|Hypervisor"
free -m
df -hT /
systemd-detect-virt

Ours printed 8 cores, AMD EPYC 7742 64-Core Processor with Hypervisor vendor: KVM, and kvm from systemd-detect-virt on the server itself (lxc inside our test container). If you bought a KVM VPS and see lxc or openvz, you are in a container, not a full virtual machine.

Now install the tools. This step needs root:

# as root
apt update
apt install -y sysbench fio iperf3 mtr-tiny sysstat curl

Debian's iperf3 package may ask whether to start iperf3 as a background service. Answer No, because you only need it as a client.

Check 1: CPU speed with sysbench

sysbench's CPU test calculates prime numbers over and over and counts how many rounds ("events") it finishes per second. Higher is better. Run it once on one thread and once on every vCPU:

# as a normal user
sysbench cpu --cpu-max-prime=20000 --threads=1 --time=30 run
sysbench cpu --cpu-max-prime=20000 --threads=$(nproc) --time=30 run

The line to read is events per second. Ours:

# output, 1 thread
CPU speed:
    events per second:   596.70
# output, 8 threads
CPU speed:
    events per second:  4763.33

--cpu-max-prime=20000 sets how far each round counts, --threads sets how many cores work at once, and --time=30 runs for 30 seconds so a short burst does not flatter the result. The single-thread number predicts how fast one request in PHP, Python or Node.js runs. The more telling check on a shared server is the ratio: 4,763 divided by 597 is 7.98, so eight vCPUs did almost exactly eight times the work of one. If yours manage only four or five times, the vCPUs are fighting busy neighbours or the plan is capped below what it advertises.

Compare only runs with identical flags: the same machine scored 1,575 events per second with the default prime limit of 10,000.

Check 2: memory bandwidth

# as a normal user
sysbench memory --memory-block-size=1M --memory-total-size=20G --memory-oper=write --threads=1 run
sysbench memory --memory-block-size=1M --memory-total-size=20G --memory-oper=read --threads=1 run

Read the MiB transferred line. We got 19640.51 MiB/sec for writes and 43266.90 MiB/sec for reads, and 47,909 MiB/s for writes with 8 threads. This test is rough and mostly hits the CPU cache, so it will not rank two good servers. It does catch a broken one: a small fraction of these figures on a modern CPU, or swap growing in free -m during the test, means the host is short of real RAM.

Check 3: disk speed with fio, without destroying anything

fio is the standard disk benchmark. It measures IOPS (input/output operations per second: how many small reads or writes the disk completes each second), throughput in MB/s, and latency (how long each request waits). Always point it at a file in your home directory, never at a device like /dev/sda or /dev/vda: a write test against a device overwrites whatever is on it.

Random 4k reads and writes: the database number

# as a normal user
mkdir -p ~/fio-test && cd ~/fio-test
fio --name=randread --filename=testfile --size=2G --rw=randread --bs=4k \
    --ioengine=libaio --iodepth=32 --numjobs=4 --direct=1 \
    --runtime=30 --time_based --group_reporting
fio --name=randwrite --filename=testfile --size=2G --rw=randwrite --bs=4k \
    --ioengine=libaio --iodepth=32 --numjobs=4 --direct=1 \
    --runtime=30 --time_based --group_reporting

What the flags mean:

Our results:

# output, random read
  read: IOPS=62.2k, BW=243MiB/s (255MB/s)(7294MiB/30002msec)
     |  99.00th=[ 3687], 99.50th=[ 3916]
# output, random write
  write: IOPS=53.3k, BW=208MiB/s (219MB/s)(6252MiB/30001msec)
     |  99.00th=[ 4228], 99.50th=[ 4752]

The 99.00th figure is in microseconds: 99 out of 100 reads finished within 3.7 ms while 128 requests were queued at once. For comparison, one 2026 benchmarking guide calls about 20,000 4k IOPS decent for a shared vCPU plan (Bitdoze, 25 September 2026). A YABS-style mixed run (50% reads, 50% writes, queue depth 64, 2 workers) gave us 30,500 reads plus 30,600 writes per second.

One request at a time: what your app actually feels

Big queues show capacity, but a small website or database with a few users sends one request at a time. The second command adds --fsync=1, which forces every write onto the disk the way PostgreSQL and MySQL do when they commit:

# as a normal user, still in ~/fio-test
fio --name=qd1 --filename=testfile --size=2G --rw=randread --bs=4k \
    --ioengine=libaio --iodepth=1 --direct=1 --runtime=20 --time_based
fio --name=qd1w --filename=testfile --size=2G --rw=randwrite --bs=4k \
    --ioengine=libaio --iodepth=1 --direct=1 --fsync=1 --runtime=20 --time_based

We got 7,855 reads per second with a median of 112 microseconds (0.11 ms), and 5,318 synced writes per second with a median sync time of 149 microseconds. That is local NVMe behaviour. Network storage adds a round trip to every request and spinning disks need several milliseconds, so an "NVMe" plan with multi-millisecond single requests deserves a question.

Sequential speed, then clean up

# as a normal user, still in ~/fio-test
fio --name=seqwrite --filename=bigfile --size=16G --rw=write --bs=1M \
    --ioengine=libaio --iodepth=8 --direct=1 --group_reporting
fio --name=seqread --filename=bigfile --size=16G --rw=read --bs=1M \
    --ioengine=libaio --iodepth=8 --direct=1 --group_reporting
rm -f testfile bigfile

Writing the 16 GiB file took 5.4 seconds (3,028 MiB/s) and reading it back took 2.5 seconds (6,583 MiB/s). Sequential speed matters for archives, video and large downloads, much less for websites. Treat very high sequential reads on any VPS, ours included, with care: the physical host may cache part of the data, and you cannot rule that out from inside the virtual machine. The 4k numbers are harder to flatter. The last line deletes the test files, so ls ~/fio-test should now show nothing.

Check 4: real bandwidth with iperf3 and a big download

iperf3 measures raw throughput between two machines, so you need a server at the other end. Several networks run public ones; these worked from Amsterdam on test day:

# as a normal user
iperf3 -c ams.speedtest.clouvider.net -p 5201 -P 4 -t 10
iperf3 -c ams.speedtest.clouvider.net -p 5201 -P 4 -t 10 -R
iperf3 -c lon.speedtest.clouvider.net -p 5201 -P 4 -t 10

-c names the server, -p picks a port (Clouvider's servers listen on 5200 to 5209; if one is busy, try another), -P 4 opens four parallel streams and -t 10 runs for 10 seconds. Without -R you measure upload from your VPS; with it, the server sends to you. Read the receiver line:

# output, upload to Clouvider Amsterdam
[SUM]   0.00-10.03  sec  7.55 GBytes  6.46 Gbits/sec                  receiver
# output, download from Clouvider Amsterdam (-R)
[SUM]   0.00-10.00  sec  6.77 GBytes  5.82 Gbits/sec                  receiver

Across four public servers we measured 4.9 to 6.5 Gbit/s inside Amsterdam and about 3.2 Gbit/s in both directions to London. A single stream reached 2.3 to 4.2 Gbit/s. A one-stream download of OVH's 1 GB test file over HTTPS took 2.8 seconds, about 3 Gbit/s:

# as a normal user
curl -s -o /dev/null -w "%{size_download} bytes in %{time_total}s = %{speed_download} B/s\n" https://proof.ovh.net/files/1Gb.dat

The result is limited by the slowest of your port, the path and the far server. Public test servers are shared with strangers, so a gap between 6.5 and 4.9 Gbit/s says more about the targets than about the VPS. Another provider's 1 GB test file downloaded at 644 Mbit/s once and 381 Mbit/s on a second try a few minutes later. On a plan with a 1 Gb/s port, about 940 Mbit/s is the practical ceiling. The red flag is a low number to every target, at every hour.

Ookla's Speedtest CLI is the other common option. It installs from Ookla's own repository and asks you to accept Ookla's licence on first run; we did not run it here. Debian's speedtest-cli package is a different, unofficial Python tool.

Check 5: latency and routing with ping and mtr

Bandwidth is how wide the pipe is; latency is how long a round trip takes, and for SSH, game servers and APIs it matters more. Test the places your users actually are:

# as root
ping -c 10 -q 1.1.1.1
ping -c 10 -q lon.speedtest.clouvider.net
mtr --report --report-cycles 20 -n fra.speedtest.clouvider.net
mtr --report --report-cycles 20 -n -T -P 443 lon.speedtest.clouvider.net

-c 10 sends ten pings and -q prints only the summary. mtr combines ping and traceroute: it probes every router on the path 20 times and prints a table, and -n shows IP addresses instead of looking up names. The last line sends TCP probes to port 443 (-T -P 443) instead of pings, which is useful when a network treats pings differently from real traffic. We ran these as root because our test container lacked the network permission plain users normally get for ping. From Amsterdam we saw 1.5 ms to Cloudflare's 1.1.1.1, 0.5 ms to Google's 8.8.8.8, 6.1 ms to London and 6.7 ms to Frankfurt, all with 0% loss.

An mtr report is easy to misread. This was our TCP report to London:

# output (shortened)
HOST: wf-bench                    Loss%   Snt   Last   Avg  Best  Wrst StDev
  3.|-- ???                       100.0    20    0.0   0.0   0.0   0.0   0.0
  5.|-- 206.148.26.155             0.0%    20    5.4   5.6   5.4   6.7   0.3
  7.|-- ???                       100.0    20    0.0   0.0   0.0   0.0   0.0
  9.|-- 5.180.211.133              0.0%    20    6.2   6.3   6.2   6.5   0.1

Lines with ??? and 100% loss are routers that are configured not to answer pings. They still forward your traffic, which is why the last line shows 0% loss. In the same way, one router in our 1.1.1.1 report had a worst time of 10.1 ms while the destination stayed fast. Only loss or delay that starts at one hop and continues to the final line is a real problem. Distance sets the floor: light in fibre covers roughly 100 km per millisecond of round trip, so Amsterdam to London can never be much under 4 ms.

Check 6: CPU steal time, the oversold-host detector

VPS plans, ours included, run on shared physical CPUs. Each vCPU is a slice of time on a real core, and the hypervisor (the software that runs virtual machines, KVM in our case) decides who runs when. When your VPS wants the CPU but the host gives that moment to another customer, Linux counts it as steal time. A little is normal. A lot, for a long time, means more vCPUs were sold than the hardware can serve, and your app slows down even though your own server looks idle.

The trick is to watch steal while the CPU is busy, because an idle VPS asks for nothing and so has nothing to lose. Start the CPU test in one SSH window and watch in another. It runs for 20 seconds, so start the watch commands straight away, or raise --time:

# as a normal user, window 1
sysbench cpu --threads=$(nproc) --time=20 run

# as a normal user, window 2
vmstat 1 10
mpstat -P ALL 5 1
sar -u 1 3

In vmstat, read the st column at the far right and ignore the first line, which is an average since boot. In mpstat and sar, read %steal. top shows the same value as st in its %Cpu(s) line. Our server under full load on all 8 vCPUs:

# output, vmstat under load (shortened)
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 9  0      0 3917904      0 249804    0    0     0     0 2166  242 100  0  0  0  0
 8  0      0 3917908      0 249804    0    0     0     0 2135  112 100  0  0  0  0
# output, mpstat
Average:     CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
Average:     all   99.95    0.00    0.02    0.00    0.00    0.02    0.00    0.00    0.00    0.00

That is 0% steal on every vCPU at 100% use. One caveat: our host was quiet when we tested, and any shared host shows brief steal when neighbours get busy. What you are looking for is a pattern, such as steal above 5% for minutes at a time every evening. To catch it, log steal over a day or two with your monitoring; our guide to Uptime Kuma and Grafana shows how to collect server metrics.

YABS: the one-line alternative, and why we did it by hand

YABS (Yet Another Bench Script) is a popular community script that runs fio (a 50/50 random mix at 4k, 64k, 512k and 1M blocks), iperf3 (8 streams to servers in Europe, the Americas and Asia) and Geekbench 6 in one go, with Geekbench 7 behind a flag since July 2026. -i, -f and -g skip the network, disk and Geekbench parts. It is handy for comparing your result with thousands posted online. We ran the individual commands instead, because each one shows which flag produced which number, and because YABS is usually started by piping a downloaded script into bash, which you should only do after reading it.

When the numbers look wrong

Run the same command again at a different hour: one bad run is noise, the same bad result at 10:00, 15:00 and 21:00 is a pattern. Check in top that no package update was running during the test. Then keep the evidence (the exact command, the full output, the time, and a vmstat or mtr report from the same moment) and send it to your provider. A good host can explain a number or fix it. If you are learning Linux, these checks are a good first exercise; our Linux and DevOps lab guide builds on the same tools.

Frequently asked questions

What is a good CPU steal time on a VPS?

Steal of 0 to 1 percent most of the time is normal on a shared vCPU, and short spikes are expected when neighbours get busy. Steal that stays above 5 percent for long periods means the host is oversubscribed. Measure it while your own CPU is busy, because an idle server shows no steal even on a crowded host.

Is it safe to run fio on a server with data on it?

Yes, as long as fio writes to a test file, such as --filename=testfile in your home directory, and you delete that file afterwards. Never point a write test at a device such as /dev/sda or /dev/vda, because that overwrites the disk. On a busy production server, run the tests at a quiet time, since they use the disk heavily for a few minutes.

Why is my iperf3 speed lower than my port speed?

Throughput is limited by the slowest part of the path: your port, the routes in between and the shared test server. Use 4 to 8 parallel streams with -P, test the other direction with -R, and try several servers. A 1 Gb/s port tops out at about 940 Mbit/s of real data.

How many IOPS should an NVMe VPS have?

For 4k random reads at a queue depth of 32, tens of thousands of IOPS is a healthy result; one 2026 guide calls about 20,000 decent on a shared plan. Our Amsterdam server measured 62,200 read and 53,300 write IOPS. Also check single-request latency: on local NVMe it should be well under a millisecond.

Is it safe to run the YABS script?

YABS is open source and widely used, but the usual one-line start pipes a downloaded script straight into bash. Download it, read it, then run it. It writes a temporary test file for fio, sends traffic to public iperf3 servers, and runs Geekbench unless you add -g.

Test one of ours the same way

Run this checklist on any server before you move real work onto it, and run it again whenever something feels slow. Every RS Computers plan is a KVM VPS or VDS with NVMe storage, unmetered traffic and its own IPv4 and IPv6 address, in Amsterdam, Dublin and Prishtina; availability by city is on the plans page. If a plan turns out too small, you can upgrade to a bigger one from the client area with a short reboot. Compare the VPS and VDS plans, and if your benchmark numbers on one of our servers look wrong, send the output to us on Telegram and we will look at it with you.

← All articles

Chat on Telegram