AWS RDS Basics: Managed Relational Databases
A practical introduction to Amazon RDS: supported engines, instance types, backups and snapshots, multi-AZ deployments, parameter groups, and security.
What you'll learn
- ✓Which database engines RDS supports and how to choose one
- ✓How to pick an instance class and storage type
- ✓How RDS handles backups, snapshots, and point-in-time recovery
- ✓What Multi-AZ deployments do for availability
- ✓How parameter groups and security groups control behavior and access
Prerequisites
- •A basic understanding of relational databases and SQL
- •Familiarity with [What is AWS](/blog/what-is-aws) and [EC2](/blog/aws-ec2-basics)
Amazon Relational Database Service (RDS) takes the operational pain out of running a database. Instead of provisioning a server, installing packages, configuring replication, and writing your own backup scripts, you make a few API calls and AWS handles the rest. This article walks through the parts of RDS you will touch most often.
Supported engines
RDS supports six engines, each with its own quirks:
- Amazon Aurora — AWS’s own MySQL- and PostgreSQL-compatible engine, with storage that auto-scales up to 128 TiB and replicas that share the same storage layer.
- PostgreSQL — full upstream PostgreSQL, currently up to version 16 on most regions.
- MySQL — standard MySQL 5.7 and 8.0.
- MariaDB — MariaDB 10.x.
- Oracle — bring-your-own-license or license-included.
- SQL Server — Express, Web, Standard, and Enterprise editions.
If you do not have an existing license or compatibility requirement, Aurora PostgreSQL or PostgreSQL are usually the easiest places to start. Aurora costs slightly more per hour but its storage and replication model pays for itself at scale.
Instance classes and storage
An RDS instance has two cost drivers: the instance class (CPU and memory) and the storage (size and IOPS).
Instance classes follow the same naming pattern as EC2:
- db.t4g / db.t3 — burstable, cheap, good for dev and small workloads.
- db.m6g / db.m7g — general purpose, balanced CPU and memory.
- db.r6g / db.r7g — memory-optimized, for workloads with large working sets.
- db.x2g — extreme memory, for in-memory analytics.
Storage options:
- General Purpose SSD (gp3) — the default. Baseline 3,000 IOPS, scales independently of size.
- Provisioned IOPS (io1 / io2) — for workloads that need predictable high IOPS.
- Magnetic — legacy, avoid for new deployments.
You can enable storage autoscaling so RDS grows the volume when free space drops below a threshold. This prevents the dreaded 3 a.m. “disk full” page.
Creating an instance
A minimal CLI command to spin up a PostgreSQL instance:
aws rds create-db-instance \
--db-instance-identifier orders-db \
--db-instance-class db.t4g.small \
--engine postgres \
--engine-version 16.2 \
--allocated-storage 20 \
--storage-type gp3 \
--master-username dbadmin \
--master-user-password 'change-me-please' \
--backup-retention-period 7 \
--multi-az \
--vpc-security-group-ids sg-0123456789abcdef0
This creates a Multi-AZ instance with a 7-day backup retention window. The endpoint comes back as something like orders-db.abc123.us-east-1.rds.amazonaws.com:5432.
Backups and snapshots
RDS gives you two backup mechanisms:
- Automated backups run daily during a configurable window and retain transaction logs for up to 35 days. Together they enable point-in-time recovery (PITR) to any second within the retention window.
- Manual snapshots are user-initiated and persist until you delete them. They are the right way to capture a known-good state before a migration.
Restoring always creates a new instance — RDS never overwrites an existing one. Plan for the DNS endpoint to change and update connection strings accordingly, or use Route 53 CNAMEs in front of RDS.
aws rds create-db-snapshot \
--db-instance-identifier orders-db \
--db-snapshot-identifier orders-db-pre-migration
aws rds restore-db-instance-to-point-in-time \
--source-db-instance-identifier orders-db \
--target-db-instance-identifier orders-db-recovered \
--restore-time 2026-06-17T22:45:00Z
Multi-AZ for high availability
A Multi-AZ deployment maintains a synchronous standby replica in a different Availability Zone. If the primary fails — hardware fault, AZ outage, or planned maintenance — RDS automatically fails over by flipping the DNS endpoint to the standby. Failover usually completes in 60 to 120 seconds.
The standby is not readable. It exists purely for availability. If you need read scaling, add read replicas, which are asynchronous and serve SELECT traffic.
Aurora is a special case: its storage is replicated six ways across three AZs at the storage layer, and you can add up to 15 readers that share that storage.
Parameter groups and option groups
A DB parameter group is a named bundle of engine configuration settings — things like max_connections, shared_buffers, or work_mem for PostgreSQL. RDS ships default parameter groups, but you cannot modify them. To change settings:
- Create a custom parameter group.
- Modify the parameters you care about.
- Associate it with your instance.
- Reboot if the parameter is marked
static.
aws rds create-db-parameter-group \
--db-parameter-group-name orders-pg-16 \
--db-parameter-group-family postgres16 \
--description "Custom params for orders service"
aws rds modify-db-parameter-group \
--db-parameter-group-name orders-pg-16 \
--parameters "ParameterName=log_min_duration_statement,ParameterValue=500,ApplyMethod=immediate"
Option groups handle engine-specific features that are not parameters, such as Oracle TDE or SQL Server SSAS. Most PostgreSQL and MySQL users never need them.
Security groups and network access
RDS instances live inside a VPC subnet group, and access is controlled by a VPC security group attached to the instance. The security group acts as a stateful firewall: only the ports and source IPs you allow can reach the database.
A typical setup:
- Place the RDS instance in private subnets so it has no public IP.
- Attach a security group that only allows port 5432 (or 3306 for MySQL) from the security group of your application servers.
- Connect from local laptops via a bastion host or AWS Systems Manager Session Manager — never by opening the database to
0.0.0.0/0.
Combine this with IAM database authentication (PostgreSQL and MySQL) to issue short-lived tokens instead of static passwords, and you have a fairly hardened setup.
Cost considerations
RDS bills for:
- Instance hours (whether or not the database is being used).
- Allocated storage and IOPS.
- Backup storage beyond 100% of provisioned size.
- Data transfer out of the region.
To control cost, stop dev instances when not in use (RDS automatically restarts them after seven days), use db.t4g burstable classes for low-traffic workloads, and consider Aurora Serverless v2 for spiky or unpredictable load.
Wrap up
RDS removes most of the toil from running a relational database, but it does not remove the need to think. Choose the right engine, size the instance for your working set, enable Multi-AZ for anything you care about, lock down the security group, and let automated backups do their job. With those basics in place, you can spend your time on schemas and queries instead of patching.
From here, a natural next step is to wire RDS into application code running on EC2 or Lambda, and to revisit how secrets reach the application — ideally through IAM database auth or AWS Secrets Manager rather than environment variables.