The Straight Answer: How to Calculate Database Capacity
If you’re asking how do I calculate capacity for a database, the practical formula is: measure current size in GB, add a realistic overhead multiplier for indexes and engine internals, project daily growth over your retention window, then multiply by replication and free-space factors. Too many teams stop at how do you calculate storage capacity as if it’s just row counts times column widths. In my first major sizing effort for a PostgreSQL logging pipeline, I made exactly that mistake—I estimated 120 GB of raw JSON, ignored index bloat and a standby replica, and we hit disk pressure in 11 weeks instead of the projected 9 months. This guide gives you the database-agnostic walkthrough I wish I had: SQL to check DB size in GB, a forecasting template, and the non-storage limits that actually cause outages.
Capacity is not a single number; it’s a composite of storage, connection, and throughput ceilings. The framework below works for PostgreSQL, MySQL, SQL Server, and Oracle with minor SQL swaps. You’ll also find a link to our interactive Database Capacity Calculator that automates the math.
Step 1: Check Your Current Database Size in GB (Across Engines)
The most common search query is how to check db size in GB. The answer is engine-specific SQL, but the conversion logic is universal: retrieve allocated bytes from system catalogs, then divide by the appropriate power of 1024 or 1000.
PostgreSQL: pg_database_size
Run the following in psql or any client:
SELECT round(pg_database_size('app_prod')/1024.0/1024.0/1024.0, 2) AS size_gb;
This returns binary gigabytes (GiB). The function accounts for tables, indexes, and visibility map files. I always round to two decimals to avoid false precision. For official behavior, see the PostgreSQL documentation.
MySQL: information_schema Summation
MySQL lacks a single size function, so sum data and index lengths per schema:
SELECT round(SUM(data_length+index_length)/1024/1024/1024, 2) AS size_gb FROM information_schema.tables WHERE table_schema='app_prod';
This excludes undo logs and binary logs, which can be substantial. The MySQL reference manual notes these columns are approximations for InnoDB.
SQL Server and Oracle Quick Hits
On SQL Server, EXEC sp_spaceused returns database_size in MB; divide by 1024. Oracle’s DBA_SEGMENTS summed by bytes gives block-level allocation. The principle remains: trust the engine’s own catalog over file system du because sparse files mislead.
How Do You Calculate GB? Binary vs Decimal
Here is the gotcha that skews forecasts: how do you calculate GB from bytes? Storage vendors and cloud bills use decimal (1 GB = 1,000,000,000 bytes), while databases return binary (1 GiB = 1,073,741,824 bytes). That 7.4% gap seems small until you’re forecasting 5 TB—then it’s 374 GB of “missing” space. I standardize on GiB internally but report decimal GB to finance to match AWS invoices.
Early in my career, a finance team budgeted for 10 TB of SAN storage based on my decimal GB report, but the DBA team provisioned 10 TiB (binary) volumes. The 10% gap surfaced as a $40k emergency purchase. Since then, I label units explicitly: GiB for tech, GB for procurement.
Another edge case: a deleted row in PostgreSQL isn’t reclaimed until VACUUM; pg_database_size includes dead tuples. InnoDB may not shrink ibd files after deletes. Always pair size checks with bloat queries before forecasting.
Step 2: Decompose Storage Components and Apply Overhead Multipliers
When a CTO asks how do you calculate storage capacity, they usually mean raw table data. Real capacity includes indexes, write-ahead logs, replication, and free headroom. The table below is the multiplier model I’ve refined across six production migrations.
| Component | Typical Multiplier | When It Spikes |
|---|---|---|
| Base table data | 1.0× | Always present |
| Secondary B-tree indexes | 0.5×–1.5× | High cardinality, UUID keys |
| GIN / full-text indexes | 1.0×–2.5× | Array or text search columns |
| WAL / redo / undo | 0.1×–0.3× of daily churn | Long transactions, replication lag |
| Replication factor | 2×–3× | Standby, multi-region |
| Free space headroom | 20%–30% | Autovacuum, defrag, spikes |
Most people don’t realize that under heavy UPDATE/DELETE workloads, PostgreSQL index bloat can push the index multiplier beyond 2.5×. I once audited a 40 GB table with 160 GB of indexes because a missing foreign-key index caused per-row cascades and page splits.
The thing nobody tells you about storage math: your index size is a function of your write pattern, not just your row count. Measure bloat with
pgstattuplebefore trusting any estimate.
Replication: Synchronous vs Asynchronous
Synchronous replication writes to standby before commit, doubling write I/O but not necessarily doubling stored bytes if the standby shares a snapshot. Asynchronous standby still stores full copy, so replication factor holds. But cascade replicas can reduce factor; I’ve used a 1-primary-2-standby chain with only 2.2× total storage instead of 3×.
Common Misconception: “Row Count × Column Width”
Beginners calculate capacity as rows × sum(column_bytes). That ignores NULL compression, alignment padding, and page overhead (24-byte heap header per row in Postgres). On a table with 20 nullable boolean columns, actual storage can be 40% less than naive math—or 30% more if you use wide uuid primary keys with random insertion causing fragmentation. Expertise means knowing when the shortcut fails.
Step 3: Forecast Future Capacity with a Repeatable Formula
To answer how do I calculate capacity for next quarter, use this template: Future_GB = (Current_GB × Overhead_Multiplier) + (Daily_Growth_GB × Retention_Days × Replication_Factor). It’s deliberately linear; exponential growth needs separate compound modeling.
Worked Example With Real Numbers
Suppose current measured size is 50 GiB, overhead multiplier 1.6, daily growth 0.4 GiB, retention 120 days, one standby (rep factor 2). Calculation: (50×1.6)=80; growth part = 0.4×120×2=96; total = 176 GiB. Add 25% free space => 220 GiB needed. That’s the number to provision, not 50.
To skip manual math, our Database Capacity Calculator encodes this with sliders for replication and compression. I keep a spreadsheet version for audits because it shows the formula lineage to stakeholders.
Variable Retention and Legal Holds
Retention isn’t always a single number. A SaaS client stored 30 days of live data but 7 years of archived invoices in a cold table. I split the formula: hot capacity uses 30-day growth; cold capacity is a one-time 1.2 TB lump with 0 growth. If you mix them, you’ll over-provision hot storage and waste money.
Example With Compression Enabled
If the same 50 GiB dataset uses 3× ZFS compression on table data but indexes stay same, effective base changes. Original overhead 1.6 included index. Compression may cut table half, new overhead ~1.3. I plug into the calculator to avoid manual error and recalc replication on the reduced figure.
When Linear Forecasting Fails
If user count doubles every period, use compound formula Current × (1 + daily_rate)^days. But beware: most startups overestimate linearity; I’ve seen churn flatten growth after month 3. Validate with 4 weeks of actual ingestion rates before committing capital.
Step 4: Plan Non-Storage Limits – Connections, IOPS, and Throughput
The thing nobody tells you about database capacity: storage is the easiest limit to expand; connection and CPU exhaustion will down your app while disk is half full. When capacity planning, treat max_connections and query latency as first-class constraints.
Connection Pooling Math
If your app uses 200 microservice instances × 10 connections each, that’s 2,000 potential connections. PostgreSQL defaults to 100. You need PgBouncer or a managed proxy. Estimate active concurrent queries as (core_count × 2) for OLTP. For load testing, our Load Capacity Calculator helps model concurrent request ceilings before you hit FATAL: remaining connection slots are reserved.
A Real Connection Storm
During a Kubernetes rollout, 300 pods each opened 20 connections before readiness probe succeeded, exploding to 6,000 attempts. The pooler saved us, but only because we had set max_client_conn correctly. Capacity planning must include failure-mode bursts, not just steady state.
IOPS and Storage Throughput
Cloud volumes throttle IOPS; a 200 GiB SSD may cap at 3,000 IOPS. If your write workload needs 5,000, you’re capacity-limited despite having free GB. Measure with pg_stat_io or sys.dm_io_virtual_file_stats. I’ve seen a 100 GiB database unable to handle Black Friday because of a 1,000 IOPS ceiling, not space.
Memory as a Capacity Dimension
Buffer pool or shared_buffers must hold your working set. If active data exceeds RAM, you thrash disk. A rough rule: size memory to 25%–40% of hot dataset. This is why capacity isn’t just “how many GB on disk”.
Step 5: The Unified Database Capacity Checklist and Decision Matrix
I distilled the above into a 7-point field checklist used in my last three migrations:
- 1. Measure current size in GB/GiB via engine SQL (Step 1).
- 2. Identify table/index bloat with pgstattuple or InnoDB stats.
- 3. Apply overhead multiplier from the table above.
- 4. Record 14-day average daily growth, not a guess.
- 5. Multiply by replication and retention needs.
- 6. Add 25% free space buffer for autovacuum/defrag.
- 7. Verify connection pool and IOPS headroom.
Decision Matrix for Scaling
Beyond the checklist, use this matrix: if forecasted size > 70% of current volume limit but IOPS headroom > 40%, scale up storage only. If connection saturation > 80%, add a read replica or pooler before adding disk. For a 400 GiB forecast on a 512 GiB volume with 70% IOPS used, scale storage to 1 TB but keep compute. This nuanced approach prevents wasted spend.
The framework is database-agnostic; swap the SQL in step 1 and keep the rest. It bridges piecemeal tips and enterprise docs precisely.
Common Mistakes I’ve Made So You Don’t Have To
When I first tried to size a database for a healthcare app, I trusted the vendor’s “average row size” white paper. The real rows were 3× larger due to embedded JSON. Mistake one: never trust vendor averages without sampling your own data.
Mistake two: ignoring seasonal spikes. A retail client’s Black Friday dumped 10× daily growth for 3 days; linear formula missed it. Now I add a spike buffer of 15% for any consumer-facing system.
Mistake three: forgetting that deleting data doesn’t free disk immediately. After a massive purge, we still got page alerts until VACUUM FULL ran offline. Capacity must account for cleanup downtime and the temporary space it needs.
Advanced Edge Cases: Compression, Partitioning, and Cloud Quirks
Compression Changes the Math Asymmetrically
SQL Server columnstore or PostgreSQL ZFS compression can shrink data 4×–10×. But indexes often remain uncompressed. Factor that asymmetry: a 100 GB table may become 15 GB, but its 50 GB index stays 45 GB. I learned this when a “10× savings” claim from a vendor didn’t materialize at the volume level.
Partitioning Turns Growth into a Cap
Daily partitions let you drop old data instantly, turning retention from a growth multiplier into a fixed cap. I migrated a 2 TB audit table to monthly partitions and cut forecast by 70% because old partitions were archived to object storage.
Multi-Tenant Considerations
In a shared schema, one noisy tenant can blow growth forecasts. I segment metrics per tenant to catch outliers; a single client once accounted for 60% of unexpected expansion in a 800 GB instance.
Managed Service Hidden Caps
Amazon RDS PostgreSQL has a max database size per instance class, not just volume limit. Always check the official RDS limits before committing. Aurora Serverless v2 scales compute but storage still grows until you delete. No managed service absolves you from the math.
Trade-off: over-provisioning wastes money; under-provisioning risks 3am pages. I recommend reviewing capacity quarterly with real metrics, not annual guesses. Uncertainty is inherent—always keep a 20% buffer for the unknown.
Putting the Calculator Template to Work
In one engagement, we caught a 40% month-over-month growth spike in a telemetry DB before it crossed 80% disk, saving a weekend outage. The key was repeatability: every sprint, re-run step 1–4. Capacity calculation isn’t a one-time task; it’s a feedback loop.
Combine measurement, forecasting, and operational limits and you’ll stay ahead. Use the SQL snippets, the multiplier table, and the checklist as living documents. And if you want the spreadsheet equivalent, the Database Capacity Calculator is ready.