SSD Nodes Learn Hosting plans →
Guides Matt ConnorBy Matt Connor

How fast is a storage VPS disk, really?

Sequential throughput and random IOPS are two different numbers. See which one a cheap storage VPS gives you, and measure your own volume with fio.

The short answer

A storage VPS disk is fast at one job and slow at another, and the two jobs get confused constantly. Sequential throughput, the rate at which the volume moves one long file, is usually good. Random IOPS (input/output operations per second), the small scattered reads and writes a database makes, is usually poor. That split is not a defect. It is what you bought when you chose terabytes over speed, and it decides which workloads belong on the box.

No published figure answers this for your volume. Capacity plans differ in disk type, in array shape, and in whether the storage sits inside the machine running your VM at all. So the second half of this guide is a measurement you run yourself with fio, on the volume you were sold, before you move anything important onto it.

Sequential throughput and random IOPS measure different things

A sequential workload reads or writes one long run of blocks in order. A random workload jumps between locations that have nothing to do with each other. On a mechanical disk that difference is physical: the head has to move to the right track and the platter has to turn under it before any data can transfer. A sequential run pays that positioning cost once and then streams. A random pattern pays it on every single operation, so the drive spends most of its time getting into position instead of moving data. The same disk therefore produces two results that look like they came from different hardware.

Two settings decide the number, which is why an IOPS figure quoted on its own means nothing. The first is block size: 4k random reads and 1M sequential reads are different questions asked of the same device. The second is queue depth. A program that waits for each read to finish before issuing the next one is limited by latency alone, while a deeper queue lets the array work on many requests at the same time. When someone quotes IOPS at you, ask for the block size and the queue depth next to it, or discard the number.

Array shape moves both numbers too. More independent disks means more heads that can be seeking at once, which is why how a RAID 10 array is built out of mirrored pairs matters far more for random work than for streaming. Parity arrays add a read-modify-write step to every small write, so small random writes are their worst case.

Why a storage VPS is good for restic, rsync and media

Backup targets and media servers ask for exactly the pattern these disks do well.

restic groups your data into pack files of several megabytes instead of writing one object per source file. A backup of a million small files therefore arrives at the target as a stream of large writes. The random half of that work, chunking and deduplication, happens on the machine holding the source data, not on the storage box.

Streaming reads a file in order from start to finish, and the player buffers ahead of what you are watching, so extra latency on each read never reaches the viewer. That is why running Jellyfin against a large library works well on capacity storage. One caution: transcoding is CPU work, not disk work. Capacity plans are usually thin on CPU, so a library that plays without transcoding is fine, and one that forces a transcode for every client is not.

rsync is the case that depends on your data. Copying disk images or video files is sequential. Copying a source tree, a Maildir or a node_modules directory is not. rsync walks the tree, stats every file, and by default writes each destination file under a temporary name and then renames it. That is thousands of small metadata operations, and metadata operations are random work. The bytes transferred look tiny while the run takes hours. If your rsync source is many small files, expect the storage box to be the slow half.

Why it is bad for a database, a mail spool or a build server

A database commit is not a bandwidth problem. PostgreSQL writes the transaction to its write-ahead log and calls fsync before it tells the client that the commit succeeded. The client is waiting for one small write to become durable. Your commit rate is therefore bounded by write latency, and no amount of sequential throughput improves it. PostgreSQL ships pg_test_fsync, which reports how many of those durable writes per second a volume can retire. Run it on the storage volume and on your main server's disk. The gap between the two is the reason not to move the database.

A mail spool has the same shape. Maildir stores one file per message and the delivery agent syncs each one, so the disk sees a stream of tiny synchronous writes. Package installs, container image pulls, git operations on a large repository and anything that unpacks an archive are the same workload wearing different clothes: thousands of small files, each one a metadata operation.

The symptom is easy to recognise. The machine is not busy, but everything is slow. top shows a high wa figure, which is the share of time the CPU spent waiting for I/O. iostat -x 1, from the sysstat package, shows a high await column and a %util close to full while r/s and w/s stay low. A device that is busy without moving much data is the signature of random access on capacity storage.

Is my storage VPS volume network-attached?

Often it is, and that changes the answer. On a capacity plan the terabytes frequently live on a separate storage system reached over the network, not on a disk inside the machine running your VM. Every read then crosses a link that other customers use as well. Latency picks up the network round trip on top of the disk time, and the link has a ceiling you do not control.

Start by looking at what the kernel will tell you.

findmnt -T /mnt/storage -o SOURCE,FSTYPE,OPTIONS
lsblk -d -o NAME,ROTA,SIZE,TRAN,MODEL
df -hT /mnt/storage

An FSTYPE of nfs4 or cifs is network storage with no ambiguity. A virtio block device tells you almost nothing, because the same device node can be a local NVMe partition, a spinning array in the next rack, or a distributed cluster, and the guest kernel cannot see the difference. ROTA is just as weak: it reports what the hypervisor claims, so a 0 there is not proof of flash.

Since you cannot read the answer off the system, measure the latency instead.

sudo apt update && sudo apt install -y ioping
ioping -c 20 -D /mnt/storage
ioping -c 20 -D /

-D asks for direct I/O, so the page cache cannot answer on the disk's behalf. Compare the volume against the root filesystem on a machine that is otherwise idle. A large and consistent gap is the network showing up in your results. Then run the same pair again in the evening. A latency that moves with the clock is a shared resource, and you are one of the people sharing it.

A snapshot on the same platform is not an offsite backup

Snapshots are useful and they are not backups. A provider snapshot lives in the same account, on the same platform, behind the same login. It protects you from deleting a file. It does not protect you from a failed payment closing the account, a stolen control panel password, or a platform incident that takes the storage and its snapshots together. Those copies fail at the same time because they were never independent to begin with.

Keep at least one copy on infrastructure that shares nothing with the original, which is the whole point of using a second VPS as an offsite backup target. A storage VPS is an excellent place to hold that copy. It is a poor place to hold the only copy.

How to measure your storage VPS disk speed with fio

Everything below was checked on Ubuntu 24.04 in September 2026. fio, ioping and sysstat are all in the default repositories, so no third-party source is needed.

sudo apt update && sudo apt install -y fio
sudo install -d -o "$USER" -g "$USER" /mnt/storage/fio
df -h /mnt/storage
free -g

Two rules before the first run. Pass --direct=1 on every job, because it bypasses the page cache, and a test that the cache can answer measures your RAM instead of your disk. Set --size larger than the RAM shown by free -g, for the same reason. Check df -h first so the test files fit with room to spare.

Sequential write, the number that matters for a backup target:

fio --name=seqwrite --directory=/mnt/storage/fio --rw=write \
  --bs=1M --size=8G --numjobs=1 --iodepth=8 --ioengine=libaio \
  --direct=1 --end_fsync=1 --group_reporting

Sequential read, the number that matters for streaming:

fio --name=seqread --directory=/mnt/storage/fio --rw=read \
  --bs=1M --size=8G --numjobs=1 --iodepth=8 --ioengine=libaio \
  --direct=1 --group_reporting

fio lays out its test file the first time a given job name is used, so this read job writes its file before it reads it. That is expected, and the layout phase is not part of the reported result.

Random read at 4k, the number that predicts whether a database will suffer:

fio --name=randread --directory=/mnt/storage/fio --rw=randread \
  --bs=4k --size=8G --numjobs=1 --iodepth=32 --ioengine=libaio \
  --direct=1 --runtime=300 --time_based --group_reporting

A mixed random load, which is closer to what a real application does:

fio --name=randrw --directory=/mnt/storage/fio --rw=randrw --rwmixread=70 \
  --bs=4k --size=4G --numjobs=4 --iodepth=16 --ioengine=libaio \
  --direct=1 --runtime=300 --time_based --group_reporting

Watch --numjobs on that last one. fio creates one file per job, so four jobs at --size=4G write 16G in total, not 4G. Check the free space before you start it, because filling a volume to zero free blocks is its own outage.

Read three things out of the output. bw= is throughput. IOPS= is operations per second, and it only means something next to the bs and iodepth you asked for. The clat percentiles block is the one most people skip and the one that predicts how the box will feel: the 99th percentile completion latency is the wait your slowest requests really see, and a healthy median beside a terrible 99th percentile is a queue that stalls under load.

Save the raw results rather than a screenshot of the terminal.

fio --output-format=json --output=/mnt/storage/fio/randread-1.json \
  --name=randread --directory=/mnt/storage/fio --rw=randread \
  --bs=4k --size=8G --numjobs=1 --iodepth=32 --ioengine=libaio \
  --direct=1 --runtime=300 --time_based --group_reporting

The test files are large, so remove them when you are done. rm -rf /mnt/storage/fio deletes the directory you created above and nothing else.

Publish nothing from a single run

One fio run is an anecdote. Several ordinary effects on shared infrastructure will move it.

  • The first write to blocks that have never been written can behave differently from a rewrite on thin-provisioned storage, so discard the first run and keep the ones after it.
  • A cache tier or a burst allowance can make the opening seconds look excellent while the steady state is ordinary. --time_based --runtime=300 runs long enough to show you which one you have.
  • Neighbours share the array and the link. A result at 03:00 and a result at 20:00 can disagree, so take both.

Run each job at least three times, at different hours, and report the median with the range around it. If that range is wide, the spread is the most useful thing you learned, because it is the difference between a volume you can plan around and one you cannot. The same discipline applies to every VPS number you collect, and the wider method for benchmarking a VPS honestly covers the CPU and network sides of the same problem.

The usual resolution: a small fast box plus a big slow one

Once you have your own two numbers, the design tends to write itself, and it is rarely one machine. Put the work on a small server with fast local storage: the database, the application, the container builds, the mail queue. Put the data on the capacity box: the media library, the archives, the restic repository, the logs nobody queries. Connect them over the provider's private network where one exists, or over a tunnel where it does not.

That layout is what pairing a storage VPS with your main VPS is for, and it beats buying one large fast machine, because you pay for speed only on the small part of the data that needs speed. If you are still choosing, the difference between a storage VPS and a regular VPS is this same trade stated as a product decision, what NVMe buys you over a SATA SSD covers the fast half of the pair, and working out how many terabytes you actually need keeps you from buying capacity you will never fill. Before you sign up, run the checklist for choosing a storage VPS against the plan and ask the provider directly whether the volume is local or network-attached. A provider who will not answer that question has still told you something.

FAQ

Is a storage VPS fast enough to run a database?

Usually not for the database itself. A commit waits for a small synchronous write to become durable, so throughput does not help and write latency sets your transaction rate. Run pg_test_fsync on the storage volume and on a normal server disk and compare the two figures. Keep the database on fast local storage, and use the storage VPS for its dumps and its archived write-ahead logs.

How do I know whether my storage VPS volume is network-attached?

findmnt -T /mnt/storage -o SOURCE,FSTYPE,OPTIONS names it outright when the volume is NFS or SMB. A virtio block device hides the answer, because the guest kernel sees the same device whether the storage is local or in another rack. Measure instead: run ioping -c 20 -D /mnt/storage beside the same command against /, and repeat both at different times of day. A latency that changes with the hour is shared infrastructure.

Why is my fio result much better than my real workload?

The usual cause is a missing --direct=1, which lets the page cache answer the reads, so the test measures RAM. A --size smaller than the machine's RAM does the same damage for the same reason. Short runs also flatter a volume, because a cache tier or a burst allowance can carry the opening seconds and then stop. Use direct I/O, a working set larger than RAM, and --time_based --runtime=300.

Is a provider snapshot a backup?

No. A snapshot lives in the same account on the same platform, so it protects you from your own mistake with a file and from nothing that takes the account or the platform. A closed account, a stolen panel login or a platform incident removes the original and the snapshot together. Keep one copy on infrastructure that shares nothing with the original.

Can I stream 4K video from a storage VPS?

Reading the file is sequential and the player buffers ahead, so the disk is rarely the limit. Two other things usually are. The plan's network allowance sets how many concurrent streams can leave the box, and transcoding is CPU work that capacity plans are not built for. Measure the sequential read with the fio job above, then check the CPU and the bandwidth policy before you count streams.