Home › Cloud services › Data services
guide low

Managed databases

Problem A team needing a reliable system of record must decide between running a database themselves and renting one with backups and failover. This guide answers which family of managed database fits.

RDS, Aurora, Cloud SQL, Spanner, DynamoDB, Cosmos DB and the Postgres startups: what each is for, what it costs, and the limits that bite.

postgresrdsauroradynamodbspannercosmos-dbneon
Overview

A managed database rents you a database engine plus backups, failover, patching and monitoring. Three families: managed open-source engines (Postgres/MySQL on RDS, Cloud SQL, Azure Flexible Server), cloud-native redesigns that separate compute from a replicated storage layer (Aurora, AlloyDB, Neon), and proprietary distributed stores (DynamoDB, Spanner, Cosmos DB, Bigtable) that scale horizontally but lock you to an API.

Key facts

Use when

  • You need a system of record and don't want to run backups and failover yourself.

Avoid when

  • Data > ~10 TB with heavy IOPS on a steady load, or extreme latency needs; see Self-host vs managed.

Deep dive

Service map

NeedAWSGCPAzureOthers
Postgres/MySQLRDS, AuroraCloud SQL, AlloyDBFlexible ServerNeon, Supabase, Crunchy Bridge, PlanetScale (MySQL/Postgres)
Key-value / document at any scaleDynamoDBFirestore, BigtableCosmos DBMongoDB Atlas, ScyllaDB Cloud
Globally consistent SQLAurora DSQLSpannerCosmos DB (NoSQL)CockroachDB, YugabyteDB, TiDB Cloud
Analytics warehouseRedshift, AthenaBigQuerySynapse, FabricSnowflake, ClickHouse Cloud, MotherDuck
Time seriesTimestreamBigtableData ExplorerTimescaleDB (Tiger), InfluxDB Cloud
Edge SQLite———Cloudflare D1, Turso

Price orders of magnitude (2026-ish)

SetupMonthly
RDS Postgres db.t4g.micro single-AZ (dev)order of $15-25
RDS/Cloud SQL 2 vCPU 8 GB, Multi-AZ, 200 GBorder of $250-400
16 vCPU 128 GB, Multi-AZ, 2 TB, provisioned IOPSorder of $3-6k
Aurora storage + I/O (standard)$0.10/GB-month + $0.20 per million I/Os; I/O-Optimized drops the I/O fee for ~30 % more on instance
Spannerorder of $0.9 per node-hour (1000 processing units) regional, plus storage
Neon / Supabase small projectfree to order of $20-70

Decision table

SituationChoiceWhy
New product, relational dataManaged Postgres (RDS, Cloud SQL, Neon, Supabase)Flexible, every tool supports it
Spiky or dev/preview databasesNeon or Aurora Serverless v2Branching, scale to zero
Simple key access, unpredictable huge scale, AWS shopDynamoDBNo capacity planning, single-digit ms at any size
Multi-region writes with strong consistencySpanner, CockroachDB, Aurora DSQLConsensus-replicated ranges, see Raft
Read-heavy, global usersPostgres primary + read replicas + cacheReplicas are cheap, consistency stays simple
Analytics over app dataReplicate to a warehouse or DuckDB/ClickHouse, don't query the OLTP primaryAnalytical scans kill OLTP latency
> 10 TB, steady, IOPS heavySelf-host on NVMeManaged IOPS pricing

Code

Postgres settings that matter. Managed services forbid ALTER SYSTEM; set instance-wide values in the parameter group / flags and per-role values in SQL:

-- connection hygiene, per application role (works on RDS, Cloud SQL, Azure)
ALTER ROLE app SET idle_in_transaction_session_timeout = '30s';
ALTER ROLE app SET statement_timeout = '15s';
ALTER ROLE app SET lock_timeout = '5s';
-- parameter group: log_min_duration_statement = 250, shared_preload_libraries = pg_stat_statements
-- visibility
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
SELECT query, calls, mean_exec_time, rows
FROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT 20;

Pool connections; serverless and many app replicas exhaust max_connections (order of hundreds):

; pgbouncer.ini
[databases]
app = host=mydb.cluster-xyz.eu-central-1.rds.amazonaws.com dbname=app
[pgbouncer]
pool_mode = transaction            ; no session state (SET, advisory locks) across statements
max_client_conn = 5000
default_pool_size = 40             ; ~2-4x the DB's vCPUs
server_tls_sslmode = verify-full

DynamoDB single-table access pattern (keys designed for the queries):

# idempotent insert: fails if this order already exists
aws dynamodb put-item --table-name app \
  --item '{"pk":{"S":"USER#42"},"sk":{"S":"ORDER#2026-10-20#9001"},"total":{"N":"1999"}}' \
  --condition-expression "attribute_not_exists(sk)"
# all October orders of one user: one partition, one sorted range read
aws dynamodb query --table-name app \
  --key-condition-expression "pk = :p AND begins_with(sk, :m)" \
  --expression-attribute-values '{":p":{"S":"USER#42"},":m":{"S":"ORDER#2026-10"}}'

Efficiency

  • Cost: a managed database bills instance hours, storage and I/O. A gp3 volume has a 3,000 IOPS and 125 MiB/s baseline included, up to 80,000 IOPS and 2,000 MiB/s when provisioned, with single-digit ms latency (EBS docs, as of 2026-10), so one default volume caps a database long before the CPU does. PgBouncer's default pool is 20 server connections per user/database pair (PgBouncer docs). Bound: provisioned IOPS and connection count.
  • Levers:
    • transaction pooling (pool_mode = transaction) — many client connections share few server connections (PgBouncer docs) — serverless and many app replicas
    • provision gp3 IOPS and throughput separately from size — up to 80,000 IOPS and 2,000 MiB/s (EBS docs) — I/O-bound databases
    • read replicas plus a cache — reads leave the primary (this page) — read-heavy global users
    • pg_stat_statements top-20 by total time — fix the few queries that dominate (Code above) — any Postgres
    • single-AZ for dev — HA roughly doubles instance cost (Key facts, order of) — non-production
  • Naive → standard → state of the art:
    • one connection per request on a burstable instance · connection storms, CPU credits run out
    • pooled connections, right-sized instance, gp3 with provisioned IOPS · 3,000 IOPS baseline raised on demand
    • replicated primary on local NVMe, self-hosted · IOPS bound by the device, not a volume cap (order of; see Self-host vs managed)

Implementation notes

  • Test restores: point-in-time restore creates a new instance in minutes to hours depending on size; know the number.
  • Read replicas are asynchronous; reading your own write needs the primary or a session-level LSN check.
  • Major version upgrades need a plan (blue/green deployments on RDS, logical replication otherwise).
  • Encrypt at rest by default and require TLS; put the DB in private subnets only.
  • Watch storage autoscaling: it only grows, never shrinks.

Pitfalls

  • Burstable instance classes (t-family) run out of CPU credits under steady load.
  • gp2/gp3 IOPS limits masquerade as "slow queries"; check ReadIOPS/DiskQueueDepth.
  • DynamoDB hot partitions: one key above order of 1000 writes/s or 3000 reads/s throttles regardless of table capacity.
  • Cross-region replicas and backups copy data across regions: billed as transfer.
  • Scale-to-zero databases add seconds of latency to the first request after idle.

Implementations

namelangrepoinstallverdictlicencehealthas_ofnotes
NeonRustneondatabase/neonn/a (service; self-host build per repo docs)————serverless Postgres, separated storage
PgBouncerCpgbouncer/pgbouncerbrew install pgbouncer————connection pooler, config in this page
sqlxRustgithub.com/transact-rs/sqlxcargo add sqlx————async Postgres/MySQL/SQLite client
pgBackRestCpgbackrest/pgbackrestbrew install pgbackrest————backup and point-in-time restore
PatroniPythonpatroni/patronipip install patroni————Postgres HA with a consensus store

Sources

  • Alexandre Verbitski et al., Amazon Aurora: Design Considerations for High Throughput Cloud-Native Relational Databases, SIGMOD 2017. paper
  • Mostafa Elhemali et al., Amazon DynamoDB: A Scalable, Predictably Performant, and Fully Managed NoSQL Database Service, USENIX ATC 2022. paper
  • James C. Corbett et al., Spanner: Google's Globally-Distributed Database, OSDI 2012. paper · ACM TOCS 2013. doi
  • AWS, Amazon EBS volume types (General Purpose SSD). docs · PgBouncer, Configuration. docs

Used by

Systems (1):

Alternatives and related