Multi-Cloud · lesson 6 of 8
Intermediate
5Advanced
3Also part of Multi-Cloud
8- + CloudWatch Monitoring Basics from AWS
- + Azure Monitor Basics from Azure
- + Cloud Monitoring Basics from Google Cloud
- + AWS Cost and Well-Architected Basics from AWS
- + Azure Cost Management Basics from Azure
- + GCP Cost and Billing Basics from Google Cloud
- + Availability, Regions, and the Arithmetic of Nines from Cloud Interviews
- + Scaling, Queues, and Backpressure from Cloud Interviews
Managed Databases: Picking One Across Clouds
RDS vs Azure Database for PostgreSQL vs Cloud SQL — real failover times, backup/restore mechanics, and pricing compared at an equivalent instance size.
By SkillByExample · Published
Same engine — PostgreSQL — on three managed services: Amazon RDS for PostgreSQL, Azure Database for PostgreSQL (Flexible Server), and Cloud SQL for PostgreSQL. Comparing the same engine everywhere is what makes this a fair comparison instead of a features list — the SQL is identical; what differs is the operational layer wrapped around it.
Provisioning an equivalent instance
4 vCPU / 16 GB RAM, single-zone (no HA yet), 100 GB storage, on each:
aws rds create-db-instance \
--db-instance-identifier orders-db \
--engine postgres --engine-version 16.4 \
--db-instance-class db.m6g.xlarge \
--allocated-storage 100 \
--master-username admin --master-user-password '********'
az postgres flexible-server create \
--resource-group learn-rg --name orders-db \
--location eastus --version 16 \
--sku-name Standard_D4ds_v5 --tier GeneralPurpose \
--storage-size 100 --admin-user admin --admin-password '********'
gcloud sql instances create orders-db \
--database-version=POSTGRES_16 \
--cpu=4 --memory=16GB \
--storage-size=100 --storage-type=SSD \
--region=us-central1
| Cloud | Instance class | On-demand (approx, single-AZ) |
|---|---|---|
| RDS for PostgreSQL | db.m6g.xlarge (4 vCPU, 16 GB) | ~$0.307 / hr |
| Azure Database for PostgreSQL | Standard_D4ds_v5 (4 vCPU, 16 GB) | ~$0.300 / hr |
| Cloud SQL for PostgreSQL | custom 4 vCPU / 16 GB | ~$0.295 / hr |
List prices, single region, single-AZ — a real quote will differ by region and changes over time, but the spread between the three (under 5%) has held for years and is worth trusting more than any single number in this table.
Failover behavior
All three use the same underlying technique — a synchronously replicated standby, promoted on failure, with the client-facing endpoint repointed rather than the client needing to know a new address.
aws rds failover-db-cluster --db-cluster-identifier orders-db-cluster
$ aws rds describe-events --source-identifier orders-db --source-type db-instance --duration 5
{
"Events": [
{"Message": "Multi-AZ instance failover started", "Date": "2026-09-13T10:12:01Z"},
{"Message": "Multi-AZ instance failover completed", "Date": "2026-09-13T10:12:47Z"}
]
}
RDS Multi-AZ failover here: 46 seconds. RDS keeps the same endpoint DNS name and flips the CNAME target during failover — the application reconnects to the same hostname and gets the new primary once DNS propagates (usually within the client’s connection retry window).
Azure’s zone-redundant HA and Cloud SQL’s regional HA follow the same shape: a synchronous standby in a second zone, promoted on health-check failure, with the connection string unchanged. Published targets put Azure Flexible Server HA failover in the tens-of-seconds range and Cloud SQL HA typically under a minute — in the same order of magnitude as RDS, with the actual number depending more on what triggered the failover (a planned test vs. a real zone outage) than on which cloud it is. Benchmark your own failover with a real client connection before trusting any vendor’s published average; run-to-run variance is usually larger than the gap between clouds.
Backup and restore
aws rds describe-db-instances --db-instance-identifier orders-db \
--query "DBInstances[0].{Retention:BackupRetentionPeriod,Window:PreferredBackupWindow}"
$ aws rds describe-db-instances --db-instance-identifier orders-db --query "DBInstances[0].{Retention:BackupRetentionPeriod,Window:PreferredBackupWindow}"
{
"Retention": 7,
"Window": "07:00-07:30"
}
aws rds restore-db-instance-to-point-in-time \
--source-db-instance-identifier orders-db \
--target-db-instance-identifier orders-db-restored \
--restore-time 2026-09-13T09:45:00Z
RDS restores to a new instance, never in place — this is true of Azure and GCP too, and is the detail that catches teams off guard during an actual incident: “restore the database” means “stand up a second instance and cut traffic to it,” not “roll this one back,” on all three clouds.
| RDS | Azure Flexible Server | Cloud SQL | |
|---|---|---|---|
| Automated backup granularity | Continuous (transaction logs) | Continuous (WAL) | Continuous (WAL) |
| PITR restore target | New instance | New server | New instance |
| Default retention | 7 days (configurable to 35) | 7 days (configurable to 35) | 7 days (configurable to 365) |
| Manual/on-demand snapshots | Yes, retained indefinitely | Yes, retained indefinitely | Yes, retained indefinitely |
Cloud SQL’s 365-day ceiling on automated retention is the one real spread in this table — useful if a compliance requirement forces long PITR windows without a manual snapshot-management process on top.
Practice
1. Query the current retention window on each provisioned instance and change it to 14 days.
aws rds modify-db-instance --db-instance-identifier orders-db --backup-retention-period 14 --apply-immediately
az postgres flexible-server parameter set --resource-group learn-rg --server-name orders-db --name backup_retention_days --value 14
gcloud sql instances patch orders-db --backup-start-time=03:00 --retained-backups-count=14
Three different flag names for the same setting — --backup-retention-period, a server
parameter, and --retained-backups-count — worth noting before assuming Terraform
provider arguments will look alike either.
2. Enable HA (multi-zone) on each instance after the fact, without recreating it.
aws rds modify-db-instance --db-instance-identifier orders-db --multi-az --apply-immediately
az postgres flexible-server update --resource-group learn-rg --name orders-db --high-availability ZoneRedundant
gcloud sql instances patch orders-db --availability-type=REGIONAL
All three can add HA without downtime scheduling flexibility varying — RDS and Cloud SQL apply this at the next maintenance window unless forced immediately; Azure applies it online in most configurations. Check the specific provider’s current behavior before assuming “no downtime” applies unconditionally.
3. Restore each instance to a point 30 minutes in the past and note what changes about the connection endpoint.
All three produce a new instance with a new endpoint hostname — orders-db-restored,
not orders-db. The application’s connection string has to change (or a proxy/DNS layer
in front of it has to be repointed), which is the step most runbooks forget to script
until the first real incident.
4. Compare provisioned IOPS pricing for the same 100 GB volume at 3000 IOPS on all three clouds.
aws rds describe-db-instances --db-instance-identifier orders-db --query "DBInstances[0].StorageType"
RDS bills provisioned IOPS separately from storage GB once you exceed the baseline
included with gp3/io1; Azure’s Flexible Server bundles a baseline IOPS-per-GB ratio
into its storage tier with a paid upgrade path; Cloud SQL ties IOPS to disk size on SSD
persistent disks with a separate provisioned-IOPS SKU for higher throughput. This is the
line item most likely to make three “equivalent” instances diverge in a real invoice.
Next: an actual monthly cost — not a features comparison — for 1M invocations on Lambda, Azure Functions, and Cloud Run.