Many organizations have applications that have been running on MySQL for years. These applications may contain hundreds of SQL queries, stored procedures, database repositories, and services that depend on the existing database structure.
As the application grows, the database infrastructure may need better availability, scalability, and operational management.
Amazon Aurora MySQL is one option for addressing these requirements without completely rewriting the application.
Aurora supports MySQL-compatible connectivity, which means applications can often continue using their existing database drivers, SQL queries, and data access layers.
However, moving to Aurora does not mean simply copying the database and changing the server address. Developers must evaluate compatibility, migrate database objects, transfer existing data, validate application behavior, and plan the production cutover.
In this article, we will explore how to move an existing MySQL application to Amazon Aurora MySQL while keeping changes to the application code to a minimum.
Understand What Can Remain Unchanged
Before starting the migration, identify which parts of the application depend on MySQL.
A typical .NET application might have the following architecture:
ASP.NET Core Application
|
v
Repository Layer
|
v
MySQL Connector
|
v
MySQL Database
After migration, the architecture can remain almost identical:
ASP.NET Core Application
|
v
Repository Layer
|
v
MySQL Connector
|
v
Aurora MySQL
The application continues communicating through the MySQL protocol.
In many cases, the following components can remain unchanged:
- Existing SQL queries.
- Repository implementations.
- Stored procedure calls.
- Entity Framework Core database access.
- MySqlConnector or compatible MySQL drivers.
- Database entity models.
- Existing business logic.
The main application-level change may be the database connection configuration.
However, this depends on the source MySQL version, Aurora engine version, authentication configuration, and database features used by the application.
MySQL compatibility does not guarantee that every extension, server variable, storage engine, or administrative operation is supported.
Assess the Existing MySQL Database
The first migration activity should be a database assessment.
Do not start by exporting production data. First, understand what the application currently uses.
Collect information about:
- MySQL engine version.
- Database size.
- Number of tables.
- Indexes and constraints.
- Stored procedures and functions.
- Triggers and scheduled events.
- Storage engines.
- Database users and permissions.
- Authentication plugins.
- Replication configuration.
- Current connection count.
- Peak transactions per second.
For example, you can inspect the MySQL version:
SELECT VERSION();
Check the database sizes:
SELECT
table_schema AS DatabaseName,
ROUND(
SUM(data_length + index_length) / 1024 / 1024,
2
) AS SizeMB
FROM information_schema.tables
GROUP BY table_schema
ORDER BY SizeMB DESC;
Identify the storage engines used by tables:
SELECT
ENGINE,
COUNT(*) AS TableCount
FROM information_schema.tables
WHERE table_schema = 'AppDb'
GROUP BY ENGINE;
These checks help identify compatibility issues before the migration begins.
For example, if the application depends on a particular storage engine or MySQL-specific plugin that Aurora does not support, that dependency must be addressed separately.
Also, select the Aurora version carefully. Aurora MySQL 3.x provides MySQL 8.0 compatibility, while Aurora MySQL 8.4 provides MySQL 8.4 compatibility.
The source and target versions should be checked against AWS migration requirements before selecting the migration path.
Choose the Right Migration Approach
The migration method depends on where the existing MySQL database is running.
There are several options.
| Existing database | Recommended migration approach |
|---|
| Self-managed MySQL on a server | Native MySQL tools, AWS DMS, or physical migration |
| Amazon RDS for MySQL | Aurora read replica or snapshot migration |
| Large external MySQL database | Evaluate physical migration or AWS DMS |
| Smaller database with acceptable downtime | Logical migration using mysqldump |
| Database requiring minimal downtime | Full load followed by ongoing replication |
AWS supports both logical and physical migration approaches.
Logical migration transfers database objects and data through SQL statements or database migration tools.
Physical migration transfers database storage files or uses compatible backup mechanisms.
Physical migration can be significantly faster for large databases, while logical migration can be easier to manage for smaller databases.
Do not choose a migration method based only on database size. Consider downtime requirements, source infrastructure, compatibility, network bandwidth, and operational complexity.
Prepare the Aurora MySQL Cluster
Before transferring data, create the target Aurora MySQL cluster.
Using the Amazon RDS console:
- Open Amazon RDS.
- Select Databases.
- Choose Create database.
- Select Amazon Aurora as the engine.
- Choose the MySQL-compatible edition.
- Select the required engine version.
- Configure the database credentials.
- Select the VPC and subnet group.
- Configure security groups.
- Review backup and monitoring settings.
For production workloads, also configure:
- Encryption at rest.
- TLS for database connections.
- Automated backups.
- Appropriate backup retention.
- CloudWatch monitoring.
- Database parameter groups.
- Maintenance windows.
- Reader instances where required.
Keep the target database configuration close to the existing application's requirements.
For example, review SQL mode, character sets, collations, time zones, and parameter differences before migrating.
The target cluster should be fully tested before it receives production traffic.
Migrate the Database Using Native MySQL Tools
For a smaller self-managed MySQL database, mysqldump is one of the simplest logical migration options.
It exports database objects and data as SQL statements that can be imported into another MySQL-compatible database.
For example:
mysqldump \
--single-transaction \
--routines \
--triggers \
--events \
--databases AppDb \
--user migration_user \
--host source-mysql.example.com \
--result-file=AppDb.sql
The single-transaction option provides a consistent snapshot for transactional tables such as InnoDB, provided the export is performed under the appropriate conditions.
Now import the dump into Aurora:
mysql \
--host aurora-cluster.example.amazonaws.com \
--user migration_user \
--password \
< AppDb.sql
This is a basic logical migration example.
For a large production database, consider parallel export and import tools, physical migration options, or a managed migration service instead of relying on one large SQL dump.
Also remember that database users and permissions may require separate handling. Do not assume that exporting application tables automatically recreates every server-level account and privilege.
Use AWS Database Migration Service for Larger Databases
For applications that cannot tolerate a long migration window, AWS Database Migration Service (AWS DMS) is another option.
AWS DMS supports full-load migration and ongoing change data capture (CDC) for supported MySQL migration scenarios.
The process generally works as follows:
Existing MySQL Database
|
v
Initial Full Load
|
v
Aurora MySQL
|
v
Ongoing Change Replication
|
v
Migration Validation
|
v
Production Cutover
The initial full load transfers the existing data.
CDC captures subsequent changes from the source database and applies them to the target.
This allows the source application to continue operating while the target database catches up.
For homogeneous MySQL-to-MySQL migrations, AWS also provides homogeneous data migrations in DMS. These use native database tools in a managed migration environment.
Before selecting this approach, review its current limitations. For example, homogeneous data migrations do not provide built-in data validation, so an additional validation process is necessary.
For a migration that requires ongoing replication and additional validation capabilities, evaluate the appropriate AWS DMS migration type and configuration.
The source database must also be configured correctly for CDC, including binary logging and the required replication permissions.
Keep the Application Code Unchanged
Once the database has been migrated and validated, the application can connect to Aurora using its existing MySQL driver.
Consider an existing ASP.NET Core application with this configuration:
{
"ConnectionStrings": {
"DefaultConnection": "Server=mysql.example.com;Port=3306;Database=AppDb;User ID=appuser;Password=secret;"
}
}
The application uses the connection string through its existing repository or database context.
After migration, update the database hostname:
{
"ConnectionStrings": {
"DefaultConnection": "Server=aurora-cluster.example.amazonaws.com;Port=3306;Database=AppDb;User ID=appuser;Password=secret;SslMode=VerifyFull;"
}
}
The important difference is the connection endpoint.
The SQL queries and repository implementation do not necessarily need to change.
For example, an existing MySqlConnector implementation can continue using the same query:
const string sql = """
SELECT CustomerId, CustomerName, Email
FROM Customers
WHERE CustomerId = @CustomerId;
""";
The application still opens a MySqlConnection and executes the query.
For production, move credentials into AWS Secrets Manager or another secure configuration provider. Also configure the trusted certificate authority required for TLS certificate verification.
If the application uses Entity Framework Core, the existing MySQL provider may continue working, provided its version supports the selected Aurora-compatible engine and required authentication settings.
This is why a compatibility test should be performed before changing the production connection string.
Validate the Migrated Database
A successful migration task does not automatically prove that the target database is correct.
Before switching production traffic, validate the data and database objects.
Important checks include:
| Validation | What to verify |
|---|
| Table count | Expected tables exist |
| Row count | Source and target record counts match |
| Indexes | Required indexes are present |
| Constraints | Primary and foreign keys are correct |
| Stored procedures | Procedures execute successfully |
| Triggers | Expected trigger behavior is preserved |
| Data types | Values are converted correctly |
| Application queries | Existing SQL executes successfully |
| Transactions | Commit and rollback behavior is correct |
You can compare row counts for important tables:
SELECT COUNT(*) FROM Customers;
Run the same query against the source and target databases.
For more reliable validation, use checksums or row-level comparison for critical tables. Be careful with tables that continue receiving writes during migration because their counts can change between checks.
Also, test the application against the target database in a staging environment.
Verify login, transactions, API requests, background jobs, reporting, and any scheduled database operations.
Plan the Production Cutover
The final step is switching application traffic from MySQL to Aurora.
A controlled cutover is important because both databases may contain different data if the source is still receiving writes.
A typical cutover process looks like this:
Prepare Aurora
|
v
Complete Initial Migration
|
v
Start Ongoing Replication
|
v
Validate Target Database
|
v
Stop Application Writes
|
v
Wait for Replication to Catch Up
|
v
Verify Final Data Consistency
|
v
Update Application Connection
|
v
Enable Application Traffic
|
v
Monitor Application
Before cutover, prepare a rollback plan.
For example, if the target database fails validation, the application should remain on the original MySQL database.
After the application begins writing to Aurora, switching back to the original database becomes more complicated because new writes may exist only on the target.
Do not assume that changing the connection string back automatically reverses the migration.
Define the rollback conditions, data reconciliation process, and decision deadline before starting the production cutover.
Monitor the Application After Migration
Once production traffic reaches Aurora, monitor both the database and the application.
Important database metrics include:
- CPU utilization.
- Database connections.
- Freeable memory.
- Read and write latency.
- Deadlocks.
- Replica lag.
- Storage usage.
- Query execution time.
For Aurora, Performance Insights and CloudWatch Database Insights can help identify database workload problems.
Also monitor application-level metrics such as API latency, failed requests, connection errors, and database timeout exceptions.
The application may continue working without code changes but still behave differently under the new infrastructure.
For example, connection pooling, reader routing, database instance sizing, and query execution plans can influence application performance.
Compare these metrics against the original MySQL environment rather than assuming that the migration automatically improves every query.
Summary
Moving an existing MySQL application to Amazon Aurora does not necessarily require rewriting the database access layer.
Aurora supports MySQL-compatible connectivity, allowing many applications to retain their existing SQL queries, repository implementations, database drivers, and business logic.
The main migration work involves assessing database compatibility, selecting the correct Aurora engine version, transferring schema and data, validating the target, and updating the database connection configuration.
For smaller databases, native MySQL tools may be sufficient. For larger databases or migrations requiring minimal downtime, AWS DMS and ongoing replication can provide a more controlled migration process.
The most important lesson is that keeping application code unchanged is a realistic goal, but it must be verified through compatibility testing and production validation. A successful database migration is not just about moving records. It is about ensuring that the existing application continues to behave correctly after the database infrastructure changes.
Join the conversation! Your thoughts help the community grow.