DatabaseIntermediate20 min read

    AWS RDS Security Best Practices

    Tarek Cheikh

    Founder & AWS Security Expert

    View Security Card

    Amazon RDS manages patching, backups, and high availability for your relational databases -- but security configuration is your responsibility. A misconfigured RDS instance can expose customer data, financial records, and PII to the internet. The shared responsibility model means AWS secures the hypervisor and host OS, while you secure everything from network access and encryption to authentication and audit logging.

    In August 2025, the nx npm supply chain attack demonstrated how quickly database infrastructure can be destroyed. Attackers injected malicious code into the popular nx build tool package, which ran during CI/CD pipelines with production credentials. The compromised pipeline connected to production RDS instances and terminated them, causing extended outages. The incident underscored why defense-in-depth for RDS -- network isolation, credential rotation, deletion protection, and proper backup retention -- is not optional.

    AWS Security Hub now includes 48 RDS-specific controls (RDS.1 through RDS.50), making automated compliance monitoring straightforward. Combined with CIS AWS Foundations Benchmark v5.0/v6.0 controls, organizations have a clear roadmap for database security. This guide covers 12 battle-tested best practices with real AWS CLI commands and audit procedures.

    1. Enable Encryption at Rest with Customer-Managed KMS Keys

    RDS encryption at rest protects the underlying storage, automated backups, read replicas, and snapshots using AES-256 encryption. Encryption must be enabled at instance creation time -- you cannot encrypt an existing unencrypted instance in place.

    Why Customer-Managed Keys (CMKs)

    • Key rotation control. CMKs support automatic annual rotation and on-demand rotation. The default aws/rds key does not allow you to manage rotation or grant cross-account access.
    • Access policies. CMK key policies let you restrict which IAM principals and AWS services can use the key, enforcing separation of duties.
    • Auditability. Every use of a CMK is logged in CloudTrail, providing a full audit trail of who decrypted what and when.

    Implementation

    # Create a CMK for RDS encryption
    aws kms create-key   --description "RDS encryption key - production databases"   --key-usage ENCRYPT_DECRYPT   --origin AWS_KMS   --tags TagKey=Environment,TagValue=production
    
    # Enable automatic key rotation (rotates annually)
    aws kms enable-key-rotation --key-id arn:aws:kms:us-east-1:123456789012:key/KEY-ID
    
    # Create an encrypted RDS instance with CMK
    aws rds create-db-instance   --db-instance-identifier prod-db   --db-instance-class db.r6g.xlarge   --engine postgres   --engine-version 16.4   --master-username admin   --manage-master-user-password   --storage-encrypted   --kms-key-id arn:aws:kms:us-east-1:123456789012:key/KEY-ID   --allocated-storage 100
    
    # Audit: Find unencrypted RDS instances
    aws rds describe-db-instances   --query "DBInstances[?StorageEncrypted==`false`].[DBInstanceIdentifier,Engine]"   --output table

    Note the --manage-master-user-password flag above. Introduced in 2023 and now a best practice, this tells RDS to generate and manage the master password in Secrets Manager automatically, eliminating manual credential management entirely.

    Security Hub Controls: RDS.3 (encryption at rest enabled). CIS Benchmark: Control 2.3.1 (RDS encryption enabled).

    2. Enforce Encryption in Transit (SSL/TLS)

    Encryption at rest protects stored data, but data in transit between your application and the database can be intercepted without TLS. Each RDS engine has its own mechanism for enforcing encrypted connections.

    Per-Engine Enforcement

    # PostgreSQL: force SSL via parameter group
    aws rds modify-db-parameter-group   --db-parameter-group-name prod-postgres-params   --parameters "ParameterName=rds.force_ssl,ParameterValue=1,ApplyMethod=pending-reboot"
    
    # MySQL / MariaDB: require secure transport
    aws rds modify-db-parameter-group   --db-parameter-group-name prod-mysql-params   --parameters "ParameterName=require_secure_transport,ParameterValue=ON,ApplyMethod=pending-reboot"
    
    # SQL Server: force encryption via rds.force_ssl
    aws rds modify-db-parameter-group   --db-parameter-group-name prod-sqlserver-params   --parameters "ParameterName=rds.force_ssl,ParameterValue=1,ApplyMethod=pending-reboot"
    
    # Oracle: use SSL option in an option group
    aws rds add-option-to-option-group   --option-group-name prod-oracle-options   --options "OptionName=SSL,OptionSettings=[{Name=SQLNET.SSL_VERSION,Value=1.2}]"

    Download and Use RDS CA Certificates

    # Download the global RDS CA bundle
    curl -o global-bundle.pem https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem
    
    # Connect with SSL verification (PostgreSQL example)
    psql "host=prod-db.abc123.us-east-1.rds.amazonaws.com   port=5432 dbname=mydb user=admin   sslmode=verify-full sslrootcert=global-bundle.pem"
    
    # Audit: Check SSL enforcement in parameter groups
    aws rds describe-db-parameters   --db-parameter-group-name prod-postgres-params   --query "Parameters[?ParameterName=='rds.force_ssl'].[ParameterName,ParameterValue]"   --output table

    Security Hub Controls: RDS.9 (database logging enabled, relates to connection auditing). Always use sslmode=verify-full (PostgreSQL) or --ssl-ca (MySQL) to prevent man-in-the-middle attacks -- sslmode=require alone does not verify the server certificate.

    3. Deploy in Private Subnets Only

    An RDS instance with PubliclyAccessible=true gets a public IP address resolvable from the internet. Even if security groups are restrictive, a publicly accessible database is one misconfiguration away from exposure. Multiple high-profile breaches have resulted from RDS instances left publicly accessible.

    Implementation

    # Create a DB subnet group using private subnets only
    aws rds create-db-subnet-group   --db-subnet-group-name prod-private-subnets   --db-subnet-group-description "Private subnets for production databases"   --subnet-ids subnet-0a1b2c3d4e5f6a7b8 subnet-0b2c3d4e5f6a7b8c9
    
    # Create instance in private subnet, explicitly disable public access
    aws rds create-db-instance   --db-instance-identifier prod-db   --db-subnet-group-name prod-private-subnets   --no-publicly-accessible   --engine postgres   --db-instance-class db.r6g.xlarge   --manage-master-user-password
    
    # Audit: Find publicly accessible instances
    aws rds describe-db-instances   --query "DBInstances[?PubliclyAccessible==`true`].[DBInstanceIdentifier,Endpoint.Address]"   --output table
    
    # Remediate: Disable public access on an existing instance
    aws rds modify-db-instance   --db-instance-identifier prod-db   --no-publicly-accessible   --apply-immediately

    Security Hub Controls: RDS.2 (no public access). This is one of the most commonly failed controls across AWS accounts. Ensure route tables for database subnets have no route to an internet gateway.

    4. Configure Security Groups for Least-Privilege Network Access

    Security groups act as a virtual firewall for your RDS instance. The principle of least privilege applies to network access just as it does to IAM policies.

    Implementation

    # Create a dedicated security group for the database
    aws ec2 create-security-group   --group-name prod-rds-sg   --description "Production RDS - allow only from app tier"   --vpc-id vpc-0a1b2c3d4e5f
    
    # Allow inbound only from the application-tier security group
    aws ec2 authorize-security-group-ingress   --group-id sg-0rds1234567890   --protocol tcp   --port 5432   --source-group sg-0app1234567890
    
    # Use a non-default port to reduce automated scanning noise
    aws rds modify-db-instance   --db-instance-identifier prod-db   --db-port-number 5433   --apply-immediately
    
    # Audit: Check for overly permissive security group rules
    aws ec2 describe-security-groups   --group-ids sg-0rds1234567890   --query "SecurityGroups[].IpPermissions[?IpRanges[?CidrIp=='0.0.0.0/0']]"   --output json
    • Reference security groups, not CIDR blocks. Source security groups automatically adapt as instances scale in and out.
    • Use non-default ports. Changing from 3306/5432/1433 to a non-standard port reduces noise from automated scanners (though it is not a security measure on its own).
    • Never use 0.0.0.0/0. No database should ever accept connections from any IP address.

    Security Hub Controls: RDS.2 (no public access), RDS.23 (no default ports for security groups).

    5. Enable IAM Database Authentication

    IAM database authentication replaces long-lived database passwords with short-lived authentication tokens generated via STS. Tokens expire after 15 minutes, drastically reducing the window of exposure if intercepted.

    Implementation

    # Enable IAM auth on the instance
    aws rds modify-db-instance   --db-instance-identifier prod-db   --enable-iam-database-authentication   --apply-immediately
    
    # Create a database user mapped to IAM (PostgreSQL)
    # Run this SQL inside the database:
    # CREATE USER iam_app_user WITH LOGIN;
    # GRANT rds_iam TO iam_app_user;
    
    # IAM policy allowing token generation
    # Attach to the application role/user:
    # {
    #   "Version": "2012-10-17",
    #   "Statement": [{
    #     "Effect": "Allow",
    #     "Action": "rds-db:connect",
    #     "Resource": "arn:aws:rds-db:us-east-1:123456789012:dbuser:dbi-resource-id/iam_app_user"
    #   }]
    # }
    
    # Generate an authentication token
    aws rds generate-db-auth-token   --hostname prod-db.abc123.us-east-1.rds.amazonaws.com   --port 5432   --username iam_app_user   --region us-east-1
    
    # Connect using the token (PostgreSQL)
    export PGPASSWORD=$(aws rds generate-db-auth-token   --hostname prod-db.abc123.us-east-1.rds.amazonaws.com   --port 5432 --username iam_app_user --region us-east-1)
    psql "host=prod-db.abc123.us-east-1.rds.amazonaws.com port=5432   dbname=mydb user=iam_app_user sslmode=verify-full   sslrootcert=global-bundle.pem"

    Supported engines: MySQL 5.7+, PostgreSQL 9.6+, MariaDB 10.6+, Aurora MySQL, Aurora PostgreSQL. IAM auth has a limit of 200 new connections per second per instance -- for high-throughput workloads, pair it with RDS Proxy.

    Security Hub Controls: RDS.10 (IAM authentication enabled).

    6. Use RDS Proxy for Connection Management and Security

    RDS Proxy sits between your application and database, providing connection pooling, failover handling, and an additional security layer. It integrates natively with IAM authentication and Secrets Manager.

    Implementation

    # Create an RDS Proxy with IAM auth and TLS required
    aws rds create-db-proxy   --db-proxy-name prod-rds-proxy   --engine-family POSTGRESQL   --auth '[{
        "AuthScheme": "SECRETS",
        "SecretArn": "arn:aws:secretsmanager:us-east-1:123456789012:secret:prod-db-creds",
        "IAMAuth": "REQUIRED",
        "Description": "Production DB credentials"
      }]'   --role-arn arn:aws:iam::123456789012:role/RDSProxyRole   --vpc-subnet-ids subnet-0a1b2c3d subnet-0b2c3d4e   --vpc-security-group-ids sg-0proxy12345   --require-tls
    
    # Register the target (your RDS instance)
    aws rds register-db-proxy-targets   --db-proxy-name prod-rds-proxy   --db-instance-identifiers prod-db
    
    # Verify TLS enforcement
    aws rds describe-db-proxies   --db-proxy-name prod-rds-proxy   --query "DBProxies[].RequireTLS"

    Security Benefits

    • IAM authentication enforcement. Set IAMAuth: REQUIRED to ensure all connections use IAM tokens.
    • TLS enforcement. --require-tls encrypts all proxy-to-client connections.
    • Secrets Manager integration. Proxy retrieves and rotates credentials from Secrets Manager automatically.
    • Connection limits. Proxy prevents connection exhaustion attacks by pooling and queuing connections.

    Security Hub Controls: RDS.12 (IAM authentication for RDS clusters).

    7. Configure Automated Backups with Adequate Retention

    Automated backups are your last line of defense against ransomware, accidental deletion, and the kind of destructive supply chain attacks like the nx incident in August 2025. A terminated instance with no backups means permanent data loss.

    Implementation

    # Set backup retention to 14 days with a preferred backup window
    aws rds modify-db-instance   --db-instance-identifier prod-db   --backup-retention-period 14   --preferred-backup-window "03:00-04:00"   --apply-immediately
    
    # Audit: Find instances with insufficient backup retention
    aws rds describe-db-instances   --query "DBInstances[?BackupRetentionPeriod < `7`].[DBInstanceIdentifier,BackupRetentionPeriod]"   --output table
    
    # Use AWS Backup for centralized, cross-account backup management
    aws backup create-backup-plan --backup-plan '{
      "BackupPlanName": "rds-daily-backup",
      "Rules": [{
        "RuleName": "DailyBackup",
        "TargetBackupVaultName": "prod-backup-vault",
        "ScheduleExpression": "cron(0 3 * * ? *)",
        "Lifecycle": {
          "DeleteAfterDays": 35
        },
        "CopyActions": [{
          "DestinationBackupVaultArn": "arn:aws:backup:eu-west-1:123456789012:backup-vault:dr-vault",
          "Lifecycle": {"DeleteAfterDays": 90}
        }]
      }]
    }'
    • Minimum 7 days retention. Production databases should use 14-35 days. Security Hub flags instances with less than 7 days.
    • Cross-region copies. Use AWS Backup copy actions to replicate snapshots to a DR region.
    • Cross-account copies. Store backup copies in a separate, locked-down backup account to protect against account compromise.

    Security Hub Controls: RDS.11 (automated backups enabled), RDS.26 (RDS DB instances should be protected by a backup plan).

    8. Secure Snapshots: Encryption and Sharing Controls

    RDS snapshots contain a full copy of your database. An unencrypted, publicly shared snapshot is equivalent to publishing your entire database on the internet.

    Implementation

    # Check each snapshot for public access (should return empty)
    for snap in $(aws rds describe-db-snapshots --snapshot-type manual --query "DBSnapshots[].DBSnapshotIdentifier" --output text); do
      aws rds describe-db-snapshot-attributes --db-snapshot-identifier "$snap"     --query "DBSnapshotAttributesResult.DBSnapshotAttributes[?AttributeName=='restore'].AttributeValues[]"     --output text | grep -q 'all' && echo "PUBLIC: $snap"
    done
    
    # Check for unencrypted snapshots
    aws rds describe-db-snapshots   --query "DBSnapshots[?Encrypted==`false`].[DBSnapshotIdentifier,DBInstanceIdentifier]"   --output table
    
    # Copy an unencrypted snapshot to an encrypted one
    aws rds copy-db-snapshot   --source-db-snapshot-identifier unencrypted-snapshot   --target-db-snapshot-identifier encrypted-snapshot   --kms-key-id arn:aws:kms:us-east-1:123456789012:key/KEY-ID
    
    # Block public snapshot sharing at the account level
    aws rds modify-db-snapshot-attribute   --db-snapshot-identifier my-snapshot   --attribute-name restore   --values-to-remove all
    
    # Use an SCP to prevent public snapshot sharing organization-wide
    # {
    #   "Version": "2012-10-17",
    #   "Statement": [{
    #     "Sid": "DenyPublicRDSSnapshots",
    #     "Effect": "Deny",
    #     "Action": "rds:ModifyDBSnapshotAttribute",
    #     "Resource": "*",
    #     "Condition": {
    #       "StringEquals": {
    #         "rds:AddAttributeValue": "all"
    #       }
    #     }
    #   }]
    # }

    Security Hub Controls: RDS.1 (no public snapshots), RDS.4 (snapshot encryption). These are among the most critical RDS controls -- a public snapshot bypasses all network and authentication controls entirely.

    9. Enable Deletion Protection

    Deletion protection prevents accidental or malicious deletion of your RDS instances. After the nx supply chain attack in August 2025, which terminated production RDS instances via compromised CI/CD credentials, deletion protection became a non-negotiable baseline control.

    Implementation

    # Enable deletion protection on an existing instance
    aws rds modify-db-instance   --db-instance-identifier prod-db   --deletion-protection   --apply-immediately
    
    # Enable on creation
    aws rds create-db-instance   --db-instance-identifier prod-db   --deletion-protection   --engine postgres   --db-instance-class db.r6g.xlarge   --manage-master-user-password
    
    # Audit: Find instances without deletion protection
    aws rds describe-db-instances   --query "DBInstances[?DeletionProtection==`false`].[DBInstanceIdentifier,Engine]"   --output table
    
    # For Aurora clusters
    aws rds modify-db-cluster   --db-cluster-identifier prod-cluster   --deletion-protection   --apply-immediately

    Deletion protection requires a two-step process to delete an instance: first disable protection, then delete. This provides a deliberate friction that prevents automated scripts or compromised pipelines from destroying databases in a single API call.

    Security Hub Controls: RDS.8 (deletion protection enabled).

    10. Enable Audit Logging Per Engine

    Database-level audit logging captures who executed what queries, when, and from where. This is essential for forensics, compliance (PCI-DSS, SOC 2, HIPAA), and detecting anomalous access patterns. RDS logs should be published to CloudWatch Logs for centralized monitoring and alerting.

    Per-Engine Configuration

    # PostgreSQL: Enable pgAudit extension
    # In your parameter group:
    aws rds modify-db-parameter-group   --db-parameter-group-name prod-postgres-params   --parameters     "ParameterName=shared_preload_libraries,ParameterValue=pgaudit,ApplyMethod=pending-reboot"     "ParameterName=pgaudit.log,ParameterValue=ddl+role+write,ApplyMethod=immediate"     "ParameterName=pgaudit.role,ParameterValue=rds_pgaudit,ApplyMethod=immediate"
    
    # MySQL / MariaDB: Enable MariaDB Audit Plugin
    aws rds modify-db-parameter-group   --db-parameter-group-name prod-mysql-params   --parameters     "ParameterName=server_audit_logging,ParameterValue=1,ApplyMethod=immediate"     "ParameterName=server_audit_events,ParameterValue=CONNECT+QUERY_DDL+QUERY_DML,ApplyMethod=immediate"
    
    # Aurora MySQL: Enable Advanced Auditing
    aws rds modify-db-cluster-parameter-group   --db-cluster-parameter-group-name prod-aurora-params   --parameters     "ParameterName=server_audit_logging,ParameterValue=1,ApplyMethod=immediate"     "ParameterName=server_audit_events,ParameterValue=CONNECT+QUERY_DDL+QUERY_DML+QUERY_DCL,ApplyMethod=immediate"
    
    # Publish logs to CloudWatch Logs
    aws rds modify-db-instance   --db-instance-identifier prod-db   --cloudwatch-logs-export-configuration     '{"EnableLogTypes":["postgresql","upgrade"]}'   --apply-immediately
    
    # For MySQL:
    aws rds modify-db-instance   --db-instance-identifier prod-mysql-db   --cloudwatch-logs-export-configuration     '{"EnableLogTypes":["audit","error","slowquery"]}'   --apply-immediately

    What to Audit

    • DDL statements: Schema changes (CREATE, ALTER, DROP) indicate potential unauthorized modifications.
    • DCL statements: Permission changes (GRANT, REVOKE) indicate privilege escalation attempts.
    • Failed connections: Brute-force login attempts.
    • DML on sensitive tables: Unusual SELECT/UPDATE patterns on tables containing PII or financial data.

    Security Hub Controls: RDS.9 (database logging enabled), RDS.34 (Aurora MySQL audit logging), RDS.36 (Aurora PostgreSQL logging to CloudWatch).

    11. Rotate Credentials with Secrets Manager

    Static database passwords that live in configuration files, environment variables, or worse -- source code -- are a persistent breach vector. AWS Secrets Manager provides automatic rotation with zero application downtime using the alternating users strategy.

    Managed Master User Password

    # New instances: use managed master user password (recommended)
    aws rds create-db-instance   --db-instance-identifier prod-db   --engine postgres   --db-instance-class db.r6g.xlarge   --manage-master-user-password   --master-user-secret-kms-key-id arn:aws:kms:us-east-1:123456789012:key/KEY-ID
    
    # Existing instances: enable managed password
    aws rds modify-db-instance   --db-instance-identifier prod-db   --manage-master-user-password   --master-user-secret-kms-key-id arn:aws:kms:us-east-1:123456789012:key/KEY-ID   --apply-immediately
    
    # Verify managed password is active
    aws rds describe-db-instances   --db-instance-identifier prod-db   --query "DBInstances[].MasterUserSecret"

    Application User Rotation with Alternating Users

    # Create a secret for application database credentials
    aws secretsmanager create-secret   --name prod/myapp/db-credentials   --secret-string '{"username":"app_user","password":"INITIAL_PASSWORD","engine":"postgres","host":"prod-db.abc123.us-east-1.rds.amazonaws.com","port":5432,"dbname":"mydb"}'
    
    # Enable rotation with the alternating users strategy
    aws secretsmanager rotate-secret   --secret-id prod/myapp/db-credentials   --rotation-lambda-arn arn:aws:lambda:us-east-1:123456789012:function:SecretsManagerRDSRotation   --rotation-rules '{"AutomaticallyAfterDays": 30}'
    
    # Retrieve the current secret in your application
    aws secretsmanager get-secret-value   --secret-id prod/myapp/db-credentials   --query "SecretString" --output text

    The alternating users strategy maintains two database users (e.g., app_user and app_user_clone). During rotation, Secrets Manager updates the inactive user's password, then switches the active label. This ensures the current password always works, even during rotation.

    Managed master passwords with Secrets Manager integration ensure credentials are never exposed and are rotated automatically.

    12. Enable Event Subscriptions for Security Alerts

    RDS event subscriptions notify you in real time when security-relevant changes occur -- configuration modifications, failovers, deletion protection changes, and security group updates. Without event subscriptions, you are flying blind between periodic audits.

    Implementation

    # Create an SNS topic for RDS security alerts
    aws sns create-topic --name rds-security-alerts
    
    # Subscribe your security team
    aws sns subscribe   --topic-arn arn:aws:sns:us-east-1:123456789012:rds-security-alerts   --protocol email   --notification-endpoint security-team@example.com
    
    # Create event subscriptions for critical categories
    aws rds create-event-subscription   --subscription-name rds-config-changes   --sns-topic-arn arn:aws:sns:us-east-1:123456789012:rds-security-alerts   --source-type db-instance   --event-categories '["configuration change","deletion","failover","failure","notification"]'   --enabled
    
    # Create a subscription for security group changes
    aws rds create-event-subscription   --subscription-name rds-security-group-changes   --sns-topic-arn arn:aws:sns:us-east-1:123456789012:rds-security-alerts   --source-type db-security-group   --event-categories '["configuration change","failure"]'   --enabled
    
    # Create a subscription for snapshot events
    aws rds create-event-subscription   --subscription-name rds-snapshot-events   --sns-topic-arn arn:aws:sns:us-east-1:123456789012:rds-security-alerts   --source-type db-snapshot   --event-categories '["creation","deletion","restoration"]'   --enabled
    
    # List all event subscriptions
    aws rds describe-event-subscriptions   --query "EventSubscriptionsList[].[CustSubscriptionId,SourceType,EventCategoriesList]"   --output table

    Route SNS notifications to a security SIEM, a Slack channel, or a Lambda function that triggers automated remediation. For example, a Lambda function can automatically re-enable deletion protection if it detects it was disabled.

    Security Hub Controls: RDS.19 (event notifications for critical cluster events), RDS.20 (event notifications for critical database instance events), RDS.21 (event notifications for database parameter groups), RDS.22 (event notifications for database security groups).


    Common Misconfigurations

    Misconfiguration Risk Detection
    PubliclyAccessible = true Database exposed to the internet Security Hub RDS.2; aws rds describe-db-instances --query "DBInstances[?PubliclyAccessible==`true`]"
    Unencrypted storage Data exposed if underlying storage is compromised Security Hub RDS.3; aws rds describe-db-instances --query "DBInstances[?StorageEncrypted==`false`]"
    Public snapshots (restore attribute = "all") Full database copy accessible to any AWS account Security Hub RDS.1; aws rds describe-db-snapshot-attributes
    SSL/TLS not enforced (rds.force_ssl = 0) Credentials and data transmitted in plaintext Check parameter group; aws rds describe-db-parameters
    Default port (3306/5432/1433) Targeted by automated scanners Security Hub RDS.23
    Backup retention < 7 days Insufficient recovery window for ransomware or destructive attacks Security Hub RDS.11, RDS.26
    Deletion protection disabled Instance can be destroyed by compromised CI/CD pipeline Security Hub RDS.8
    Master password in plaintext (not managed) Long-lived credentials in config files or environment variables Security Hub RDS.28; aws rds describe-db-instances --query "DBInstances[].MasterUserSecret"
    Security group allows 0.0.0.0/0 Database accepts connections from any IP address Security Hub RDS.2; aws ec2 describe-security-groups

    Quick Reference Checklist

    # Practice Priority
    1Encrypt at rest with customer-managed KMS keysCritical
    2Enforce SSL/TLS for all connectionsCritical
    3Deploy in private subnets onlyCritical
    4Configure least-privilege security groupsCritical
    5Enable IAM database authenticationHigh
    6Use RDS Proxy with IAM auth and TLSHigh
    7Automated backups with 7+ day retentionCritical
    8Encrypt snapshots, block public sharingCritical
    9Enable deletion protectionCritical
    10Enable audit logging per engineHigh
    11Rotate credentials with Secrets ManagerHigh
    12Enable event subscriptions for security alertsMedium

    Related Resources

    Go Deeper: The State of AWS Security 2026

    This article is just the start. Get the full picture with our free whitepaper - 8 chapters covering IAM, S3, VPC, monitoring, agentic AI security, compliance, and a prioritized action plan with 50+ CLI commands.

    RDSDatabaseEncryptionSSL/TLSIAM AuthRDS ProxySecrets Manager