plainstackBook a free call
← All guides

Storage10 min read

io1 vs io2 vs gp3: is provisioned IOPS worth the money?

Every other volume type bills on gigabytes. These bill again for each IOPS you reserved, whether anything uses it or not.

By Plainstack/

Every other EBS volume type bills on one thing: how many gigabytes you asked for. io1 and io2 bill on two. You pay for the storage, and then you pay again, separately, for each IOPS you reserved — whether or not anything ever issues that many requests.

That second meter is the whole guide. It is why provisioned-IOPS volumes turn up as one of the largest single line items inside EC2 — Other, and why they are so often the easiest expensive thing to fix in an AWS account.

The second meter

On gp3 you get 3,000 IOPS and 125 MB/s included with every volume, at no additional charge, no matter how small it is. You only pay extra above that, and the extra is around half a cent per IOPS per month.

On io1 and io2 there is no included allowance. Every single IOPS is billed, from the first one, at roughly thirteen times the gp3 rate. Reserve 10,000 IOPS and you are buying 10,000 IOPS every hour of every day, at rest, at idle, over a holiday weekend, forever.

500 GB AT 10,000 IOPS — MONTHLY, BY VOLUME TYPEio1$712.50STORAGE $62.50 · IOPS $650.00io2$712.50STORAGE $62.50 · IOPS $650.00gp3$75.00STORAGE $40.00 · IOPS $35.00io1 and io2 price IOPS identically up to 32,000. Above that io2 tiers down; io1 never does.
Storage is the dark segment. The coloured segment is the second meter — and on provisioned IOPS it dwarfs the thing people think they are buying.

The proportions are the point. On a 500 GB volume at 10,000 IOPS, storage is about 9% of the io1 bill. Arguing about gigabytes on a provisioned-IOPS volume is arguing about the wrong number.

What the same volume costs on each type

Move the sliders to your own volume. The comparison is like-for-like: same size, same guaranteed IOPS, four ways of buying it.

Plainstack · Provisioned IOPS modelInteractive
500 GB
10,000
io1$713 / mo
io2$713 / mo

Identical to io1 below 32,000 IOPS — but with far better durability at the same price, so there's no reason to pick io1.

gp3$75 / mo
gp2$50 / mo

Delivers only 1,500 baseline IOPS at this size — it cannot do the job.

io1 → gp3, per year$7,650

That is one volume. The decision that put it there — provision generously now, revisit once things settle down — is rarely made only once, and the revisit has no owner.

us-east-1 list prices at time of writing — storage and IOPS only, excluding snapshots and transfer. AWS changes pricing; check current rates for your region before acting on a number.

Two things usually surprise people here. The first is how flat gp3 stays — the included 3,000 IOPS covers a lot of ground, and the charge above it is small enough that gp3 remains cheaper than io1 right up to its ceiling. The second is how early gp2 becomes impossible: gp2 grants 3 IOPS per gigabyte, so a 500 GB volume tops out around 1,500 baseline IOPS. Teams that "saved money by staying on gp2" often quietly weren't getting the performance they assumed.

The three types, honestly

gp3 is the general-purpose SSD and the correct default. 3,000 IOPS and 125 MB/s included, provisionable up to 16,000 IOPS and 1,000 MB/s, with a hard ratio limit of 500 IOPS per provisioned gigabyte. That ceiling is the only reason most workloads ever need to look further.

io1 is the older provisioned-IOPS type. Up to 64,000 IOPS on Nitro instances, a 50:1 IOPS-to-GB ratio limit, and a durability figure of 99.8–99.9%. There is essentially no reason to choose io1 for something new today.

io2 supersedes it at the same per-GB storage price: 99.999% durability (two orders of magnitude better), a 500:1 ratio limit, and — the part that matters most on a bill — tiered IOPS pricing. The rate drops above 32,000 IOPS and again above 64,000. io1 charges one flat rate all the way up. At high IOPS counts io2 is not just better, it is cheaper, which is why "io1 vs io2" is rarely a real decision.

io2 Block Express is io2 on newer infrastructure, reaching 256,000 IOPS, 4,000 MB/s and 64 TiB on supported instance families. If you genuinely need numbers like those, you are not choosing between these types by reading a guide — you are choosing by benchmark.

Decide

Does this volume actually need provisioned IOPS?

Under 16,000 IOPSgp3, unless you have a measured latency requirement that gp3 has failed. This covers the overwhelming majority of database volumes.
Sustained above 16,000io2 — this is gp3's hard ceiling, and the one unambiguous reason to pay for provisioned IOPS. Confirm the number is sustained, not a nightly batch peak.
Still on io1Move to io2. Same storage price, far better durability, and cheaper above 32,000 IOPS because of tiering. There is no case for staying.
Multi-Attach across instancesio1 or io2 — gp3 cannot do this. A genuine constraint, and one of the few that isn't about performance at all.
Nobody remembers whyMeasure before you decide anything. The section below takes about ten minutes and answers it properly.

How to check what you're actually using

This is the part that decides it, and almost nobody does it, because the number isn't shown anywhere you'd naturally look. The EC2 console tells you what you provisioned. It does not tell you what you consumed.

In CloudWatch, for each volume, pull VolumeReadOps and VolumeWriteOps. These are counts per period, not rates — the most common mistake is reading them as IOPS directly and concluding the volume is idle. Convert:

IOPS = (VolumeReadOps + VolumeWriteOps) / period_seconds

For a 5-minute period, divide the sum by 300. Take the maximum over 30 days, not the average — an average across a month will make almost any volume look unused and will talk you into an under-provision you'll regret at month-end close or during a nightly batch.

Then compare that peak against what you're paying for:

  • Peak under 3,000 — gp3 covers it with the included allowance. Nothing extra to provision, and the saving is the entire IOPS charge.
  • Peak between 3,000 and 16,000 — gp3 still covers it. Provision the delta and check the 500:1 ratio holds for the volume size.
  • Peak consistently above 16,000 — io2, and you were right.

Do this before touching anything, and add ~20% headroom to the peak rather than provisioning exactly to it.

A 500 GB VOLUME WITH 80 GB ON IT80 GB420 GB of empty spaceBILLED AT THE SAME RATEYOU PAY FOR THISEBS bills on provisioned size. Volumes can grow but cannot shrink — so provision smalland let autoscaling take it up, rather than sizing for three years out on day one.
The provisioned figure is a purchase decision made once. The consumed figure is what the workload actually does. Nothing in AWS reconciles the two for you.

Why over-provisioning here is the normal outcome

It's worth understanding the mechanism, because it tells you where else to look.

The number gets chosen at the worst possible moment — during a migration or a launch, before anyone has production telemetry, when the cost of being slow is a visible incident and the cost of being generous is an invisible line in a bill nobody reads. Every incentive points the same way. So the number goes in high, with an honest intention to revisit it once things settle.

Revisiting it requires someone to notice a charge that appears inside EC2 — Other rather than under a service name, then correlate it back to a decision made months earlier by someone who may have left. That review has no owner and no trigger. It doesn't happen — not through negligence, but because nothing in the system ever asks for it.

The same shape explains oversized instances, forgotten Multi-AZ on staging databases, and 35-day backup retention nobody chose. Provisioned IOPS is just the most expensive instance of it per unit of neglect.

Making the change

The migration is an online operation. You modify the volume in place — no snapshot, no detach, no instance restart:

aws ec2 modify-volume --volume-id vol-xxxx --volume-type gp3 --iops 5000

Three things worth knowing before you run it across a fleet:

  • There's a cooldown. After modifying a volume you must wait roughly six hours before modifying it again. Get the target IOPS right the first time rather than tuning down in steps.
  • The volume stays usable throughout, though it passes through an optimizing state where performance is somewhere between the old and new configuration. Do it outside your peak window even though you technically don't have to.
  • Filesystem size is untouched. You're changing the volume's type and performance, not its capacity, so there's nothing to resize inside the guest.
0 / 7

Where this sits in the wider bill

Provisioned IOPS is one line inside EC2 — Other, the Cost Explorer bucket that also hides NAT Gateway, inter-AZ transfer, and every EBS volume you own. Split that bucket by usage type and you'll see which of them you're actually dealing with — it takes about a minute and it is the single most useful minute in Cost Explorer.

If your storage line looks larger than it should and you'd rather not spend the afternoon in CloudWatch, the free teardown reads a Cost Explorer export in your browser and tells you how much of the bill is sitting in EC2 — Other. Nothing is uploaded and there's no signup.

Check your own account

Does this apply to you? Find out in two seconds.

Drop a Cost Explorer export into the free teardown. It reads your service mix and tells you which of these patterns show up in your bill — in your browser, with no upload and no email.