Skip to content

Phase 3 · CLOUD

RDS & managed databases

Day 53 of 90 ~50 min 0/20 in phase Builds on Day 52

By the end of today

  • Explain managed RDS vs self-hosted databases and when to pick each
  • Launch a free-tier db.t4g.micro, connect to it, and take a snapshot
  • Know Multi-AZ, automated backups, and how to delete without a final snapshot

RDS and managed databases: the undifferentiated heavy lifting, handled

Section 1 of 5 · ~3 min

Almost every application needs a database, and for decades running one meant a person: install the engine, patch the OS, script the nightly backup, test the restore, and stand up a standby in case the disk dies at 3 a.m. Amazon RDS (Relational Database Service) takes that whole job and runs it for you. You choose an engine and a size; AWS provisions the server, patches it, backs it up on a schedule, and can fail over to a standby automatically. You get a connection endpoint and a database — you never SSH into the host.

That trade is the thing to understand. Self-hosting on EC2 gives you total control: any engine, any extension, root on the box. It also hands you every operational chore. RDS takes the chores — patching, backups, failover, monitoring — in exchange for giving up shell access and some deep engine tuning. For a normal relational workload the managed option wins almost every time; you self-host only when you need an engine RDS doesn’t offer or OS-level access it won’t grant.

RDS runs the engines you already know: PostgreSQL, MySQL, MariaDB, Oracle and SQL Server, plus Amazon’s own MySQL/PostgreSQL-compatible Aurora. Whichever you pick, four managed features matter today:

  • Multi-AZ — a synchronous standby copy in a second availability zone. You never query it; if the primary’s AZ fails, RDS flips the endpoint to the standby in a minute or two, with no data loss. It’s for availability, not read scaling (a read replica is the asynchronous copy you send reads to).
  • Automated backups — a daily snapshot plus transaction logs, kept 1–35 days, letting you restore to any point in time in that window. They’re deleted when the instance is.
  • Manual snapshots — a copy you take yourself that lives until you delete it, surviving the instance. Take one before a risky migration.
  • Subnet & parameter groups — a subnet group tells RDS which (ideally private) subnets it may live in; a parameter group is the engine config (like max_connections) you tune without editing a config file.
An application reads and writes to the RDS primary in availability zone A, which synchronously replicates to a standby in zone B for failover, while automated backups and manual snapshots are stored separately. App reads + writes RDS primary AZ-a Standby AZ-b, failover only Backups + snapshots point-in-time restore sync daily
RDS runs the primary, keeps a synchronous standby for failover, and backs the data up for you — the work you would otherwise do by hand on EC2.

Real world: RDS is renting an apartment instead of owning a house. Own the house (EC2) and every leaking pipe and dead boiler is your midnight problem. Rent (RDS) and the landlord patches the roof, fixes the plumbing, and keeps a spare unit ready if yours floods — you just live there. You give up knocking down a wall to suit yourself, but you never wake up to a burst pipe.

Companies lean on this hard. Airbnb runs core booking data on Amazon RDS and Aurora, letting a small platform team hand AWS the patching, backups and failover that would otherwise need a dedicated DBA rota — engineering time that goes into the product instead of babysitting a database host.

Today you launch a free-tier db.t4g.micro, connect to it, take a manual snapshot, and delete it — skipping the final snapshot so no storage lingers on the bill. That snapshot step is the one that sets up next week’s Database Recovery mission, where a restore is the only thing standing between you and a lost production table.

Hands-On Lab

Section 2 of 5 · ~4 min

Budget about 25 minutes, most of it waiting for RDS to provision. Drive this from the AWS CLI v2 as your Day 47 IAM user (not root) in us-east-1, and have a psql client installed locally. RDS launches take several minutes, so the wait commands below are doing real work — let them finish. In a real system you would never put the master password on the command line or make the DB publicly accessible; you would use AWS Secrets Manager and a private subnet. We use a throwaway password and IP-scoped public access here only so you can connect from your laptop in one sitting — and we delete all of it within the hour.

What this costs: ₹0 if you stay on the free tier and delete everything at the end. A single db.t4g.micro (or db.t3.micro) is free-tier eligible (legacy 12-month accounts: 750 hours/month + 20 GB; accounts created after mid-2025: covered by free-plan credits) — either way ₹0 if you stay single-AZ and delete everything — but only single-AZ: Multi-AZ runs a second instance and is not free, which is why step 3 passes --no-multi-az. Snapshot storage beyond your free allowance also bills, so steps 8–10 delete the instance and the manual snapshot. Leaving this DB running is roughly ₹1,000–1,400/month — the ₹0 outcome depends entirely on finishing the teardown, not walking away after you connect.

# 1. Confirm you're your Day 47 IAM user (NOT root) and pin the region.
aws sts get-caller-identity
export AWS_DEFAULT_REGION=us-east-1
# Output (your Account and Arn will differ):
# {
#     "UserId": "AIDA...EXAMPLE",
#     "Account": "123456789012",
#     "Arn": "arn:aws:iam::123456789012:user/devops-you"
# }
# 2. Find your public IP and create a security group allowing Postgres (5432) from you ONLY.
MY_IP=$(curl -s https://checkip.amazonaws.com)
SG=$(aws ec2 create-security-group \
  --group-name m90-rds --description "Postgres from my IP only" \
  --query 'GroupId' --output text)
aws ec2 authorize-security-group-ingress \
  --group-id "$SG" --protocol tcp --port 5432 --cidr "${MY_IP}/32"
echo "$SG"
# Output (your GroupId will differ — the rule is scoped to your /32, never 0.0.0.0/0):
# sg-0abc123def4567890
# 3. Launch ONE free-tier db.t4g.micro Postgres. Single-AZ (Multi-AZ is NOT free tier).
#    Uses your default VPC's default DB subnet group; public access is fenced by your SG.
aws rds create-db-instance \
  --db-instance-identifier m90-pg \
  --engine postgres --db-instance-class db.t4g.micro \
  --allocated-storage 20 --no-multi-az --publicly-accessible \
  --backup-retention-period 1 \
  --master-username dbadmin --master-user-password 'ChangeMe_9x!tmp' \
  --vpc-security-group-ids "$SG" \
  --query 'DBInstance.DBInstanceStatus' --output text
# Output:
# creating
# 4. Wait until it's available (~5-10 min), then read its connection endpoint.
aws rds wait db-instance-available --db-instance-identifier m90-pg
aws rds describe-db-instances --db-instance-identifier m90-pg \
  --query 'DBInstances[0].Endpoint.Address' --output text
# Output (yours will differ — this hostname is your DB endpoint):
# m90-pg.abcdef1234.us-east-1.rds.amazonaws.com
# 5. Connect with psql and run a query. Enter the password you set in step 3 when prompted.
psql -h m90-pg.abcdef1234.us-east-1.rds.amazonaws.com -U dbadmin -d postgres -c 'SELECT version();'
# Output (yours will differ — trimmed):
# Password for user dbadmin:
#                                   version
# ---------------------------------------------------------------------
#  PostgreSQL 16.4 on aarch64-unknown-linux-gnu, compiled by gcc ...
# (1 row)
# 6. Take a MANUAL snapshot — it survives the instance (this sets up the Database Recovery mission).
aws rds create-db-snapshot \
  --db-instance-identifier m90-pg \
  --db-snapshot-identifier m90-pg-snap1 \
  --query 'DBSnapshot.Status' --output text
# Output:
# creating
# 7. Wait for the snapshot to finish, then confirm it's stored and its type is 'manual'.
aws rds wait db-snapshot-available --db-snapshot-identifier m90-pg-snap1
aws rds describe-db-snapshots --db-snapshot-identifier m90-pg-snap1 \
  --query 'DBSnapshots[0].[DBSnapshotIdentifier,Status,SnapshotType]' --output text
# Output:
# m90-pg-snap1    available    manual
# 8. Delete the DB. --skip-final-snapshot avoids leaving a NEW snapshot behind;
#    --delete-automated-backups clears the daily ones so no backup storage lingers.
aws rds delete-db-instance \
  --db-instance-identifier m90-pg \
  --skip-final-snapshot --delete-automated-backups \
  --query 'DBInstance.DBInstanceStatus' --output text
# Output:
# deleting
# 9. Wait until the instance is fully gone — this is the step that stops the compute + storage bill.
aws rds wait db-instance-deleted --db-instance-identifier m90-pg
echo "db deleted"
# Output:
# db deleted
# 10. Delete the MANUAL snapshot too — it outlives the DB and its storage keeps billing otherwise.
aws rds delete-db-snapshot --db-snapshot-identifier m90-pg-snap1 \
  --query 'DBSnapshot.Status' --output text
# Output:
# deleted
# 11. Delete the security group and confirm no DB instances remain.
aws ec2 delete-security-group --group-id "$SG"
aws rds describe-db-instances --query 'DBInstances[].DBInstanceIdentifier' --output text
# Output (empty — no DB instances remain):
#

Read the outputs back: db deleted in step 9 stops the instance’s compute and storage charges, and step 10 clears the manual snapshot’s storage — together they are the difference between a ₹0 lab and a database quietly billing you all month. You proved the whole shape of a managed database: launch, connect, snapshot, tear down.

Common Errors & Fixes

Section 3 of 5 · ~2 min

These trip up almost everyone launching their first RDS instance. Read the error text slowly — parsing it is the actual skill.

Common error: psql hangs, then fails, because the network path to the database is closed:

psql: error: connection to server at "m90-pg.abcdef1234.us-east-1.rds.amazonaws.com" (54.x.x.x), port 5432 failed: Connection timed out

Why: A timeout (not “authentication failed”) is a network problem, not a password problem. Either the instance wasn’t launched with --publicly-accessible, the security group has no rule allowing 5432 from your address, or — the common one — your home IP changed since step 2, so the /32 rule no longer matches you.

Fix: Re-check your current IP with curl -s https://checkip.amazonaws.com, then re-run authorize-security-group-ingress for the new /32. Confirm the live rule with aws ec2 describe-security-groups --group-ids "$SG", and confirm public access with describe-db-instances --query 'DBInstances[0].PubliclyAccessible'.

How you’d spot it in prod: A DB connection that times out rather than being refused points at a security group, subnet route, or NACL — not at credentials. “Timed out” means nothing answered; “authentication failed” means the DB answered and rejected you.

Common error: Trying to snapshot or delete the instance while it is still coming up:

An error occurred (InvalidDBInstanceState) when calling the CreateDBSnapshot operation: The specified DB Instance is not in the available state.

Why: RDS operations are state-gated. A fresh instance sits in creating for several minutes; you can’t snapshot, modify or delete it until it reaches available. The API refuses rather than queuing the request.

Fix: Block on the state first — aws rds wait db-instance-available --db-instance-identifier m90-pg — before the snapshot (step 4 does exactly this). The wait command polls for you and returns only once the instance is ready.

How you’d spot it in prod: An automation step failing with InvalidDBInstanceState almost always means it raced ahead of a provisioning or modification that hadn’t finished. The fix is a wait (or a status poll), not a retry loop that hammers the API.

Common error: Deleting the instance without saying what to do about a final snapshot:

An error occurred (InvalidParameterCombination) when calling the DeleteDBInstance operation: FinalDBSnapshotIdentifier is required unless SkipFinalSnapshot is set to true.

Why: RDS assumes you probably want a parting backup, so it forces an explicit choice: either name a final snapshot to keep, or opt out with --skip-final-snapshot. It won’t silently throw the data away, and it won’t silently create billable storage either.

Fix: For a throwaway lab, pass --skip-final-snapshot (step 8) so no extra snapshot is created and no storage is left behind. For anything real, drop the flag and pass --final-db-snapshot-identifier <name> to keep one last restore point.

How you’d spot it in prod: This error on a terraform destroy or teardown script means the delete needs a snapshot decision. Choose deliberately — skip for scratch resources, keep a final snapshot for anything whose data you might ever want back.

RDS Interview Questions

Section 4 of 5 · ~1 min

Cover the answers below and say your own version out loud first — name what RDS manages, what Multi-AZ does that a read replica doesn’t, and the automated-backup versus manual-snapshot split before you reveal each answer. Recalling before revealing is what makes these stick when an interviewer asks them cold. The four questions and answers render right after this note.

Go Deeper

Section 5 of 5 · ~1 min

Optional extras if you have ~30 more minutes today:

  • 5 min — Read the RDS Multi-AZ deployments doc and note how failover flips the endpoint DNS — the reason your app reconnects to the same hostname after an AZ dies.
  • 10 min — Restore your m90-pg-snap1 snapshot into a brand-new instance with aws rds restore-db-instance-from-db-snapshot, watch it come up, then delete both — the exact restore muscle next week’s Database Recovery mission drills.
  • 15 min — Create a custom DB parameter group, change max_connections, and read why some parameters need a reboot to apply; then skim the read replica docs so you can explain, cold, why Multi-AZ is for availability and replicas are for read scaling.
What does RDS actually manage for you compared with running a database on EC2? Both

RDS is a managed database service — AWS runs the engine (PostgreSQL, MySQL and others) and handles the undifferentiated heavy lifting: OS patching, engine upgrades, automated backups, failover and monitoring. On EC2 you install and run the database yourself, and every one of those tasks is on you. The trade is control versus effort: RDS gives up shell access to the host and some deep engine tuning in exchange for taking backups, patching and Multi-AZ failover off your plate. I reach for RDS by default for a normal relational workload, and only self-host on EC2 when I need an unsupported engine, a custom extension, or OS-level access RDS won't grant.

What is Multi-AZ in RDS, and is it the same as a read replica? Both

No — people conflate them constantly. Multi-AZ keeps a synchronous standby copy of your database in a second availability zone. You never read or write to the standby; it exists only for failover. If the primary's hardware or AZ fails, RDS flips the DNS endpoint to the standby, usually within a minute or two, with no data loss. A read replica is different: it's an asynchronous copy you can actually send read queries to, so it scales read traffic — but it can lag, and promoting it on failure is manual. Rule of thumb: Multi-AZ is for availability, read replicas are for read scaling. You can run both together.

What's the difference between an automated backup and a manual snapshot in RDS? Product

Both are storage-level snapshots, but their lifecycle differs. Automated backups run daily in a window you set and, thanks to captured transaction logs, let you restore to any point in time within your retention period (1 to 35 days). Crucially, they're deleted when you delete the database instance. A manual snapshot is one you take yourself; it captures the DB at that moment and lives until you explicitly delete it — it survives the instance. So for anything I need to keep beyond the instance's life — before a risky migration, or as a long-term archive — I take a manual snapshot. That's also why deleting a test DB with 'skip final snapshot' avoids leaving snapshot storage behind.

How would you keep an RDS database's credentials and network access secure? Service

Two layers. For network, I put RDS in private subnets with no public accessibility, and scope its security group to allow the database port (5432 for PostgreSQL) only from the application's security group or my own IP — never 0.0.0.0/0. A subnet group tells RDS which subnets it may live in, which is how I keep it off the public internet. For credentials, I never hard-code the password; I store it in AWS Secrets Manager (which can rotate it automatically) or SSM Parameter Store, and let the app fetch it at runtime via an IAM role. RDS also supports IAM database authentication, so short-lived tokens replace passwords entirely. Encrypt at rest with KMS, and enforce TLS in transit.

Mark Day 53 complete

Tomorrow you put a load balancer in front of your instances and let auto scaling add and remove them as traffic rises and falls.

Stuck on today’s lab? Ask in Mission 90 Q&A