HomeArtificial Intelligence DIYData DIYHow to Create a Secure MySQL Database on AWS RDS and Aurora

How to Create a Secure MySQL Database on AWS RDS and Aurora

Introduction

Creating a MySQL database on AWS is easy.

Creating a secure MySQL database on AWS takes more thought.

That difference matters.

A database may contain customer records, payment details, order history, internal reports, application data, audit logs and business-critical transactions. If it is exposed publicly, poorly backed up, weakly monitored or configured with broad access, the risk is not theoretical. It can become a security incident, outage or data-loss event.

Amazon RDS for MySQL and Amazon Aurora MySQL-Compatible Edition are two common ways to run MySQL workloads on AWS.

RDS is a managed relational database service that reduces the operational work of running MySQL yourself.

Aurora is AWS’s cloud-native relational database engine that is compatible with MySQL and designed for higher availability and scalability.

Both can be secure.

Both can also be misconfigured.

This guide explains how to create a secure MySQL database on AWS using RDS or Aurora, what settings matter, what mistakes to avoid, and how to think about security before the database goes live.


RDS MySQL vs Aurora MySQL: Which One Should You Choose?

Before creating the database, decide whether you need Amazon RDS for MySQL or Amazon Aurora MySQL.

Both support MySQL-compatible workloads, but they are designed differently.

Choose Amazon RDS for MySQL When

RDS for MySQL is a good choice when:

  • You want a familiar managed MySQL setup.
  • Your workload is moderate or predictable.
  • You want simpler pricing and operations.
  • You are migrating from a traditional MySQL server.
  • Your application does not need Aurora-specific scale or high-availability features.
  • You want standard MySQL behavior with managed backups, patching and monitoring.

For many small and medium applications, RDS MySQL is enough.

Choose Amazon Aurora MySQL When

Aurora MySQL is a better fit when:

  • You need higher availability.
  • You expect read-heavy workloads.
  • You want faster failover design.
  • You want Aurora replicas for scaling reads.
  • You need a cloud-native MySQL-compatible database.
  • You are building a production system where resilience matters.
  • Your database is central to revenue, transactions or customer experience.

Aurora usually gives more advanced architecture, but it can also be more expensive and operationally different from standard RDS MySQL.

Practical Advice

Use RDS MySQL when you need a reliable managed MySQL database.

Use Aurora MySQL when your workload needs stronger availability, scaling and cloud-native database architecture.

Do not choose Aurora only because it sounds more advanced.

Choose it because the workload needs it.


What Makes a MySQL Database Secure on AWS?

A secure database is not created by one setting.

It is created by multiple controls working together.

A secure AWS MySQL setup should include:

  • Private network placement
  • Correct VPC and subnet design
  • Restricted security groups
  • No public exposure unless absolutely required
  • Strong master credentials
  • Secrets management
  • Encryption at rest
  • Encryption in transit
  • Automated backups
  • Multi-AZ or Aurora high availability
  • Deletion protection
  • Least-privilege access
  • Monitoring and logging
  • Patch management
  • Parameter hardening
  • Regular restore testing
  • Cost and performance monitoring

Security is not only about preventing attackers.

It is also about preventing mistakes, outages, accidental deletion and data loss.


Step 1: Start With the Right AWS Region

Choose the AWS Region where your database should live.

Consider:

  • Where your users are
  • Where your application servers run
  • Data residency requirements
  • Latency
  • Compliance
  • Availability Zone support
  • Cost differences
  • Disaster recovery strategy

For example, if your application servers are in Mumbai, placing the database in another distant region may increase latency.

A simple rule:

Keep the database close to the application unless there is a clear compliance or architecture reason not to.


Step 2: Create or Choose a VPC

Your RDS or Aurora database should run inside a VPC.

A VPC is a private network inside AWS.

For production, avoid placing your database in a public subnet unless there is a very specific reason.

A secure layout usually looks like this:

Internet
   ↓
Load Balancer / Public Subnet
   ↓
Application Servers / Private Subnet
   ↓
RDS or Aurora MySQL / Private Database Subnet

The database should normally accept connections only from the application layer, not directly from the internet.

Recommended VPC Design

Use:

  • At least two Availability Zones
  • Public subnets for load balancers
  • Private subnets for application servers
  • Private database subnets for RDS or Aurora
  • NAT Gateway only if private resources need outbound internet access
  • Security groups to restrict access
  • Route tables that do not expose the database subnet publicly

The database does not need to be publicly reachable for most applications.


Step 3: Create a DB Subnet Group

A DB subnet group tells RDS which subnets it can use.

For production, choose private subnets across at least two Availability Zones.

This helps support high availability options such as Multi-AZ.

A good subnet group may include:

private-db-subnet-az1
private-db-subnet-az2
private-db-subnet-az3

Avoid using only one Availability Zone for production workloads.

If that zone has a problem, your database availability may suffer.


Step 4: Configure Security Groups Carefully

Security groups act like virtual firewalls.

For MySQL, the default port is:

3306

A common mistake is allowing access from anywhere:

0.0.0.0/0 on port 3306

Do not do this for production databases.

A safer rule is:

Allow inbound MySQL traffic only from the application server security group.

Example:

Database security group inbound rule:
Type: MySQL/Aurora
Port: 3306
Source: Application server security group

This means only your application servers can connect to the database.

Not the whole internet.

Not every IP in your office.

Not every server in the VPC.

Only the systems that actually need database access.

Recommended Security Group Pattern

Use separate security groups:

app-sg
database-sg

Then configure:

database-sg allows inbound 3306 from app-sg

This is better than allowing broad CIDR ranges.

It is easier to manage and safer as your infrastructure grows.


Step 5: Decide Whether the Database Should Be Public

For almost all production web applications, the answer should be no.

In RDS, there is a setting called Public access.

For production:

Public access: No

A public database endpoint increases attack surface.

Even if the password is strong, exposing MySQL to the internet invites scanning, brute-force attempts and accidental misuse.

Use safer access methods:

  • Connect from application servers inside the VPC
  • Use VPN
  • Use AWS Systems Manager Session Manager
  • Use a bastion host if necessary
  • Use private networking
  • Use IAM and least-privilege admin access

Public databases should be rare, temporary and heavily restricted.


Step 6: Choose Engine: RDS MySQL or Aurora MySQL

For RDS MySQL

In the RDS console:

  1. Go to Amazon RDS.
  2. Choose Create database.
  3. Select Standard create.
  4. Choose MySQL.
  5. Select the engine version.
  6. Choose production or dev/test settings.
  7. Configure instance size, storage, credentials and networking.

For Aurora MySQL

In the RDS console:

  1. Go to Amazon RDS.
  2. Choose Create database.
  3. Select Standard create.
  4. Choose Amazon Aurora.
  5. Select Aurora MySQL-Compatible Edition.
  6. Choose the engine version.
  7. Configure cluster, writer instance, replicas, credentials and networking.

Aurora uses a cluster-based architecture.

That means you create a DB cluster and at least one DB instance.

The cluster stores the data.

The instances provide compute access.

This is different from a simple single RDS MySQL DB instance.


Step 7: Choose a Secure Master Username and Password

Avoid obvious usernames such as:

admin
root
mysql
test

Use a unique master username.

Use a strong password.

Better still, store credentials in AWS Secrets Manager.

Do not hardcode database passwords in:

  • Application code
  • GitHub repositories
  • Environment files committed to Git
  • Build scripts
  • Docker images
  • Shared documents
  • Chat messages

Database credentials should be treated like production secrets.

Better Credential Practice

Use:

  • AWS Secrets Manager
  • IAM policies
  • Rotation where possible
  • Separate users for applications
  • Separate users for admins
  • Least-privilege database grants

The master user should not be the daily application user.

Create a limited application user after database setup.


Step 8: Enable Encryption at Rest

Encryption at rest protects stored database data.

Enable encryption when creating the database.

This usually covers:

  • Database storage
  • Automated backups
  • Snapshots
  • Read replicas, depending on configuration

Use AWS KMS keys.

For many projects, AWS-managed keys are enough.

For stricter compliance, use customer-managed KMS keys.

Important point:

You usually cannot enable encryption later on an existing unencrypted RDS DB instance directly. You may need to create an encrypted snapshot and restore from it.

So decide correctly at the beginning.

For production:

Storage encryption: Enabled

Step 9: Require Encryption in Transit

Encryption in transit protects data moving between the application and database.

Use SSL/TLS for database connections.

Your application connection string should enforce TLS where possible.

For MySQL clients, this may involve:

  • Downloading the AWS RDS CA certificate
  • Configuring SSL mode
  • Updating the connection string
  • Validating the certificate
  • Ensuring drivers support TLS

Example connection idea:

mysql client/app → TLS connection → RDS/Aurora MySQL

This is especially important when applications, services or users connect across networks.

Even inside private networks, encryption in transit is a good security practice.


Step 10: Enable Automated Backups

Backups are not optional.

Enable automated backups for production databases.

Choose a backup retention period based on business needs.

Common settings:

Backup retention: 7 days, 14 days, 30 days or 35 days

A short retention period may reduce cost, but it also reduces recovery flexibility.

Ask:

  • How far back might we need to recover?
  • What is the business impact of data loss?
  • What compliance rules apply?
  • How quickly must we restore service?
  • Have we tested restore?

Backups are only useful if restore works.

Test restore regularly.


Step 11: Enable Multi-AZ for Production

Multi-AZ improves availability.

For RDS MySQL, Multi-AZ creates a standby in another Availability Zone.

For Aurora, the cluster storage is designed across multiple Availability Zones, and you can add Aurora Replicas for availability and read scaling.

Use Multi-AZ or Aurora replicas for production workloads where downtime matters.

A development database may not need Multi-AZ.

A production customer-facing database usually should.

Simple Rule

For dev/test:

Single AZ may be acceptable.

For production:

Use Multi-AZ or Aurora high-availability design.

High availability costs more, but downtime also costs money.


Step 12: Enable Deletion Protection

Deletion protection prevents accidental database deletion.

For production, enable it.

Deletion protection: Enabled

This is one of the simplest safety settings and one of the most important.

A tired engineer, wrong script or mistaken console action should not be able to delete a production database easily.

Deletion protection is not a replacement for backups, but it reduces accidental disaster risk.


Step 13: Configure Storage Correctly

For RDS MySQL, choose storage based on workload.

Consider:

  • Allocated storage
  • Storage autoscaling
  • IOPS requirements
  • Workload growth
  • Backup size
  • Cost

Enable storage autoscaling if growth is unpredictable.

This helps avoid downtime caused by running out of storage.

But still monitor usage.

Autoscaling prevents some emergencies, but it does not replace capacity planning.

For Aurora, storage grows automatically up to service limits, but you still need to monitor cost and workload behavior.


Step 14: Configure Monitoring and Logs

A secure database must be observable.

Enable monitoring early.

Use:

  • Amazon CloudWatch metrics
  • Enhanced Monitoring
  • Performance Insights
  • RDS event notifications
  • Error logs
  • Slow query logs
  • Audit logs where required
  • Database activity monitoring for sensitive workloads

Monitor:

  • CPU usage
  • Memory
  • Connections
  • Storage
  • Read/write latency
  • IOPS
  • Deadlocks
  • Replication lag
  • Slow queries
  • Failed login attempts
  • Backup status
  • Free storage
  • Database restarts

A database problem should be detected before users complain.


Step 15: Create a Limited Application User

Do not use the master user from your application.

Create a separate database user with only the permissions the app needs.

Example:

CREATE USER 'app_user'@'%' IDENTIFIED BY 'strong-password-here';

GRANT SELECT, INSERT, UPDATE, DELETE
ON app_database.*
TO 'app_user'@'%';

FLUSH PRIVILEGES;

Avoid giving the app user broad privileges such as:

GRANT ALL PRIVILEGES ON *.* TO 'app_user'@'%';

Most applications do not need admin privileges.

Use least privilege.

For reporting users, create read-only accounts.

For migration tools, use controlled elevated access only when required.


Step 16: Connect Securely From Your Application

A basic connection string may look like this:

mysql://app_user:password@database-endpoint:3306/app_database

But in production, avoid directly storing this in code.

Use:

  • Secrets Manager
  • Environment variables from secure deployment systems
  • IAM roles where applicable
  • Encrypted configuration
  • TLS options
  • Connection pooling

Also configure your application to handle database failures gracefully.

A secure database architecture is not only about access.

It is also about resilience.

The app should handle:

  • Temporary connection failures
  • Failovers
  • Connection timeouts
  • Pool exhaustion
  • Read replica lag
  • Slow queries
  • Maintenance events

Step 17: Use Parameter Groups Carefully

RDS and Aurora use parameter groups to control database engine settings.

Examples include:

  • Character set
  • Time zone
  • Logging options
  • Connection limits
  • SQL modes
  • Slow query logging
  • TLS-related parameters
  • Performance settings

Do not randomly copy parameter group settings from the internet.

Understand each change.

A bad parameter can hurt security, performance or compatibility.

For production:

  • Create a custom parameter group.
  • Document changes.
  • Test changes in staging.
  • Apply during a maintenance window when needed.

Step 18: Plan Maintenance Windows

AWS manages much of the infrastructure, but maintenance still matters.

Set a maintenance window during a low-traffic period.

Plan for:

  • Minor version upgrades
  • Security patches
  • Parameter changes
  • Instance modifications
  • Failover testing
  • Backup validation

Do not ignore maintenance because the database is “managed.”

Managed does not mean maintenance-free.


Step 19: Add Read Replicas When Needed

Read replicas help scale read-heavy workloads.

Use read replicas for:

  • Reporting queries
  • Analytics dashboards
  • Read-heavy APIs
  • Search indexing jobs
  • Background jobs
  • Reducing load on the writer

But read replicas are not magic.

They can lag behind the primary database.

Do not send read-after-write critical queries to replicas unless the application can tolerate delay.

For example, after a user updates their profile, they expect to see the update immediately.

That query should usually go to the writer or a strongly consistent path.


Step 20: Test Restore Before You Need It

Many teams enable backups but never test restore.

That is risky.

A backup strategy is incomplete until you know restore works.

Test:

  • Restoring from automated backup
  • Restoring from snapshot
  • Point-in-time recovery
  • Application connection to restored database
  • Data validation after restore
  • Recovery time
  • Recovery process documentation

Ask:

How long does restore take?

Who performs it?

Which environment is used?

How do we verify data?

How do we switch the app if needed?

A backup is a file.

A restore plan is business continuity.

You need both.


Secure RDS MySQL Setup Checklist

Use this checklist before going live.

[ ] Database is in private subnets
[ ] Public access is disabled
[ ] Security group allows 3306 only from app security group
[ ] Strong master password is used
[ ] Application does not use master user
[ ] Credentials are stored in Secrets Manager or secure config
[ ] Encryption at rest is enabled
[ ] TLS/SSL is configured for connections
[ ] Automated backups are enabled
[ ] Backup retention matches business needs
[ ] Multi-AZ is enabled for production
[ ] Deletion protection is enabled
[ ] Monitoring is enabled
[ ] Slow query logs are enabled where needed
[ ] Least-privilege database users are created
[ ] Parameter group changes are documented
[ ] Maintenance window is configured
[ ] Restore has been tested
[ ] Cost monitoring is active

This checklist will prevent many common mistakes.


Secure Aurora MySQL Setup Checklist

For Aurora MySQL, check:

[ ] Aurora cluster is created in private subnets
[ ] Public access is disabled
[ ] Cluster security group allows access only from application layer
[ ] Encryption is enabled at cluster creation
[ ] Backup retention period is configured
[ ] Deletion protection is enabled
[ ] At least one reader is configured for production where needed
[ ] Failover behavior is understood
[ ] Cluster and reader endpoints are used correctly
[ ] Monitoring and Performance Insights are enabled
[ ] Application handles failover and connection retries
[ ] Secrets are stored securely
[ ] TLS is enforced where required
[ ] Restore has been tested

Aurora gives strong architecture, but applications still need to be designed for failover and connection handling.


Common Mistakes to Avoid

Mistake 1: Making the Database Public

This is one of the most dangerous mistakes.

Keep production databases private unless there is a strong reason not to.

Mistake 2: Allowing 0.0.0.0/0 on Port 3306

Never expose MySQL broadly to the internet.

Restrict access by security group.

Mistake 3: Using the Master User in the Application

The application should use a limited user, not the master admin account.

Mistake 4: Not Enabling Backups

A production database without backups is a business risk.

Enable backups and test restore.

Mistake 5: No Multi-AZ for Critical Workloads

Single-AZ production databases are vulnerable to Availability Zone issues.

Use Multi-AZ or Aurora for critical workloads.

Mistake 6: Ignoring Slow Queries

Security and performance are connected.

A slow database can cause outages.

Enable slow query analysis and optimize indexes.

Mistake 7: Hardcoding Passwords

Never commit credentials to code.

Use a secure secrets system.

Mistake 8: No Deletion Protection

Accidental deletion happens.

Enable deletion protection for production.

Mistake 9: No Monitoring

If you are not monitoring connections, storage, CPU and latency, you are waiting for users to report problems.

Mistake 10: Not Testing Failover

High availability settings are useful only if your application handles failover correctly.


Best Practices for Production MySQL on AWS

Use private subnets.

Restrict database access with security groups.

Disable public access.

Enable encryption at rest.

Use TLS for connections.

Use Secrets Manager for credentials.

Create least-privilege database users.

Enable automated backups.

Test restores regularly.

Enable Multi-AZ for production.

Enable deletion protection.

Use Performance Insights.

Monitor slow queries.

Set alarms for storage, CPU, connections and latency.

Use read replicas carefully.

Document parameter group changes.

Patch during planned maintenance windows.

Avoid running large analytics queries on the production writer.

Use separate environments for dev, staging and production.

Review access regularly.


RDS MySQL vs Aurora MySQL: Security Difference

Security principles are similar for both.

But the architecture differs.

RDS MySQL usually revolves around a DB instance, with optional Multi-AZ and read replicas.

Aurora MySQL revolves around a DB cluster, shared cluster storage and separate writer/reader instances.

For security, both need:

  • Private networking
  • Restricted security groups
  • Encryption
  • Backups
  • Least privilege
  • Monitoring
  • Secrets management

For high availability, Aurora has a more cloud-native architecture.

But a poorly configured Aurora cluster can still be insecure.

Do not confuse advanced architecture with automatic security.

You still need to configure it properly.


DIY Build Plan: Secure MySQL for a Web Application

Here is a practical example.

Goal

Create a secure MySQL database for a production web application.

Architecture

Users
  ↓
Load Balancer
  ↓
App Servers in Private Subnets
  ↓
RDS MySQL or Aurora MySQL in Private DB Subnets

Database Settings

Engine: MySQL or Aurora MySQL
Public access: No
Encryption: Enabled
Backup retention: 7–35 days
Deletion protection: Enabled
Multi-AZ: Enabled for production
Security group: Allow 3306 only from app-sg
Monitoring: CloudWatch + Performance Insights
Credentials: Secrets Manager

Application User

CREATE USER 'app_user'@'%' IDENTIFIED BY 'strong-password';

GRANT SELECT, INSERT, UPDATE, DELETE
ON app_database.*
TO 'app_user'@'%';

FLUSH PRIVILEGES;

Reporting User

CREATE USER 'report_user'@'%' IDENTIFIED BY 'another-strong-password';

GRANT SELECT
ON app_database.*
TO 'report_user'@'%';

FLUSH PRIVILEGES;

This keeps application writes and reporting access separate.


How to Keep Costs Under Control

Security matters, but cost also matters.

RDS and Aurora costs can grow through:

  • Instance size
  • Storage
  • IOPS
  • Backups
  • Snapshots
  • Read replicas
  • Cross-region replication
  • Data transfer
  • Always-on dev databases
  • Overprovisioned production clusters

Cost-control tips:

  • Right-size instance classes.
  • Use dev/test instances only when needed.
  • Delete unused snapshots carefully.
  • Monitor storage growth.
  • Use read replicas only when needed.
  • Avoid oversized instances before query tuning.
  • Enable alarms for unusual spend.
  • Review Performance Insights before scaling up.
  • Optimize indexes and slow queries.

Do not solve every performance issue by buying a bigger instance.

Sometimes the real fix is a missing index.


Final Thoughts

Creating a secure MySQL database on AWS is not just a console setup task.

It is an architecture decision.

Amazon RDS for MySQL and Aurora MySQL both make database operations easier, but they do not remove your responsibility for secure configuration.

A production database should be private, encrypted, monitored, backed up and protected from accidental deletion.

It should allow access only from trusted systems.

It should use least-privilege users.

It should have tested restore procedures.

It should be designed for availability, not just creation.

The safest AWS database is not the one with the most expensive instance.

It is the one with the right network design, access controls, backup strategy, monitoring and operational discipline.

Start secure.

Then scale.

That is the correct way to build MySQL on AWS.


FAQs

What is the best way to run MySQL on AWS?

The most common managed options are Amazon RDS for MySQL and Amazon Aurora MySQL-Compatible Edition. RDS MySQL is simpler and familiar, while Aurora is better for higher availability and scalability needs.

Should an AWS MySQL database be public?

Usually no. Production databases should normally be placed in private subnets with public access disabled.

What port does MySQL use on AWS RDS?

MySQL commonly uses port 3306. Access to this port should be restricted using security groups.

Is Aurora MySQL more secure than RDS MySQL?

Aurora has a different high-availability architecture, but security still depends on configuration. Both RDS and Aurora need private networking, encryption, least privilege, backups and monitoring.

Should I enable encryption for RDS MySQL?

Yes. Encryption at rest should be enabled for production databases, ideally at creation time.

Should I use the master user in my application?

No. The application should use a separate database user with only the permissions it needs.

What is Multi-AZ in RDS?

Multi-AZ is a high-availability deployment option that places a standby database in another Availability Zone for failover.

What is deletion protection?

Deletion protection prevents accidental deletion of a production database unless the protection is explicitly disabled first.

How often should I test database restore?

Restore should be tested regularly, especially before major releases, compliance reviews or production migrations.

What is the biggest security mistake with RDS MySQL?

The biggest mistake is exposing the database publicly or allowing broad inbound access to port 3306.

Most Popular