Your comprehensive resource for migrating to AWS RDS SQL Server, implementing bulletproof security, and mastering cloud database operations. Covers migration strategies, DMS, backup and recovery, SSIS/SSRS configuration, security fundamentals, and operational best practices.
By Erich Brinker
Your comprehensive resource for migrating to AWS RDS SQL Server, implementing bulletproof security, and mastering cloud database operations
Moving SQL Server workloads to AWS RDS is more than just a lift-and-shift operation—it’s a strategic transformation that can dramatically reduce infrastructure overhead while enhancing scalability and reliability. However, the journey from on-premises to cloud requires careful planning, understanding of AWS-specific implementations, and knowledge of how traditional SQL Server features translate to the RDS environment.
At InFocus Data, we’ve guided dozens of organizations through successful RDS migrations, helping them avoid common pitfalls while maximizing their cloud investment. This comprehensive guide covers everything from initial migration planning through advanced security implementation and operational optimization.
Whether you’re planning your first RDS migration or looking to optimize an existing deployment, this guide provides the practical insights and real-world strategies you need for success.
Key Differences: On-Premises vs. AWS RDS Before diving into migration mechanics, it’s crucial to understand what changes when moving to RDS:
When to Use DMS vs. Native Methods AWS DMS excels in several scenarios:
DMS Architecture and Setup
-- Pre-migration assessment query
-- Run this on your source SQL Server to understand your environment
SELECT
db.name AS DatabaseName,
CAST(SUM(mf.size) * 8.0 / 1024 / 1024 AS DECIMAL(10,2)) AS SizeGB,
COUNT(DISTINCT t.object_id) AS TableCount,
MAX(p.rows) AS LargestTable
FROM sys.databases db
INNER JOIN sys.master_files mf ON db.database_id = mf.database_id
LEFT JOIN sys.tables t ON db.database_id = DB_ID(db.name)
LEFT JOIN sys.partitions p ON t.object_id = p.object_id AND p.index_id IN (0,1)
WHERE db.database_id > 4 -- Exclude system databases
GROUP BY db.name
ORDER BY SizeGB DESC;
DMS Configuration Best Practices
Source Endpoint Configuration
Target Endpoint Setup
Replication Instance Sizing
Recommended sizing based on source database:
Common DMS Migration Challenges and Solutions
-- Check for unsupported data types before migration
SELECT
t.name AS TableName,
c.name AS ColumnName,
ty.name AS DataType,
c.max_length,
c.precision,
c.scale
FROM sys.tables t
INNER JOIN sys.columns c ON t.object_id = c.object_id
INNER JOIN sys.types ty ON c.user_type_id = ty.user_type_id
WHERE ty.name IN ('text', 'ntext', 'image', 'timestamp', 'sql_variant')
ORDER BY t.name, c.column_id;
Managing Large Object (LOB) Data DMS handles LOB data differently than standard columns. Configure your task settings appropriately:
{
"TargetMetadata": {
"LobChunkSize": 64,
"LimitedSizeLobMode": true,
"LobMaxSize": 32
}
}
Native Backup and Restore with S3 For smaller databases or when DMS isn’t suitable:
-- Create credential for S3 access (run on source SQL Server)
CREATE CREDENTIAL [https://your-bucket.s3.amazonaws.com/]
WITH IDENTITY = 'S3 Access Key',
SECRET = 'YourSecretKey';
-- Backup to S3
BACKUP DATABASE [YourDatabase]
TO URL = 'https://your-bucket.s3.amazonaws.com/database-backup.bak'
WITH COMPRESSION, CHECKSUM, STATS = 10;
AWS Database Migration Assessment Before any migration, use the AWS Schema Conversion Tool (SCT) to assess compatibility and generate migration reports.
Automated Backups vs. Manual Snapshots AWS RDS provides two backup mechanisms, each with distinct use cases:
Automated Backups:
Manual DB Snapshots:
-- Monitor backup status and timing
SELECT
backup_start_date,
backup_finish_date,
DATEDIFF(minute, backup_start_date, backup_finish_date) AS backup_duration_minutes,
backup_size,
database_name,
type
FROM msdb.dbo.backupset
WHERE database_name = 'YourDatabaseName'
ORDER BY backup_start_date DESC;
Setting Up S3 Integration with RDS Unlike on-premises SQL Server, RDS requires specific configuration to interact with S3:
Create S3 VPC Endpoint
Configure RDS Option Groups
-- After setting up the S3 integration option group
-- You can then use BACKUP/RESTORE commands with S3
-- Example: Restore from S3 backup
EXEC msdb.dbo.rds_restore_database
@restore_db_name='RestoredDatabase',
@s3_arn_to_restore_from='arn:aws:s3:::your-bucket/backup-file.bak';
S3 Backup Best Practices
-- Create a stored procedure for S3 backup with error handling
CREATE PROCEDURE sp_BackupToS3
@DatabaseName NVARCHAR(255),
@S3Path NVARCHAR(500)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @BackupName NVARCHAR(500);
DECLARE @SQL NVARCHAR(MAX);
-- Generate timestamped backup name
SET @BackupName = @DatabaseName + '_' + FORMAT(GETDATE(), 'yyyyMMdd_HHmmss') + '.bak';
SET @S3Path = @S3Path + @BackupName;
BEGIN TRY
-- Log backup start
INSERT INTO BackupLog (DatabaseName, BackupType, StartTime, Status)
VALUES (@DatabaseName, 'S3 Backup', GETDATE(), 'Started');
-- Execute S3 backup
EXEC msdb.dbo.rds_backup_database
@source_db_name = @DatabaseName,
@s3_arn_to_backup_to = @S3Path;
-- Update log on success
UPDATE BackupLog
SET EndTime = GETDATE(), Status = 'Completed'
WHERE DatabaseName = @DatabaseName
AND StartTime = (SELECT MAX(StartTime) FROM BackupLog WHERE DatabaseName = @DatabaseName);
END TRY
BEGIN CATCH
-- Log error
UPDATE BackupLog
SET EndTime = GETDATE(),
Status = 'Failed',
ErrorMessage = ERROR_MESSAGE()
WHERE DatabaseName = @DatabaseName
AND StartTime = (SELECT MAX(StartTime) FROM BackupLog WHERE DatabaseName = @DatabaseName);
-- Re-raise error
THROW;
END CATCH
END;
Implementing Disaster Recovery For mission-critical applications, implement cross-region backup replication:
-- Monitor cross-region snapshot copy status
SELECT
DBSnapshotIdentifier,
SnapshotCreateTime,
Status,
AvailabilityZone,
AllocatedStorage
FROM rds_snapshots
WHERE SourceRegion != 'current-region'
ORDER BY SnapshotCreateTime DESC;
Automated Cross-Region Replication Strategy
What’s Different in RDS:
Option Group Configuration SSRS on RDS requires careful setup through Option Groups:
-- After SSRS option is added to your RDS instance
-- Configure SSRS database connection
USE master;
GO
-- Create SSRS service account login
CREATE LOGIN [ssrs_service] WITH PASSWORD = 'ComplexPassword123!';
CREATE USER [ssrs_service] FOR LOGIN [ssrs_service];
-- Grant necessary permissions for SSRS
ALTER SERVER ROLE dbcreator ADD MEMBER [ssrs_service];
ALTER SERVER ROLE sysadmin ADD MEMBER [ssrs_service]; -- Temporary for initial setup
SSRS Configuration Steps:
Add SSRS Option to Option Group
Initialize SSRS Database
-- Connect to SSRS Configuration Manager equivalent
-- (Done through RDS console or AWS CLI)
-- Verify SSRS installation
SELECT
SERVERPROPERTY('ProductVersion') AS SQLServerVersion,
SERVERPROPERTY('ProductLevel') AS ProductLevel,
SERVERPROPERTY('Edition') AS Edition;
Configure Report Server Database
-- Check SSRS databases after configuration
SELECT name, database_id, create_date
FROM sys.databases
WHERE name LIKE 'ReportServer%';
Since SSIS can’t run directly on RDS, consider these alternatives:
Option 1: EC2-Hosted SSIS with RDS Connection
-- Connection string for SSIS packages connecting to RDS
Data Source=your-rds-endpoint.amazonaws.com,1433;
Initial Catalog=YourDatabase;
Integrated Security=False;
User ID=your-username;
Password=your-password;
Encrypt=True;
TrustServerCertificate=True;
Option 2: Azure Data Factory (Hybrid Approach)
Option 3: AWS Glue as SSIS Alternative
# Example AWS Glue job for data transformation
import sys
from awsglue.transforms import *
from awsglue.utils import getResolvedOptions
from pyspark.context import SparkContext
from awsglue.context import GlueContext
from awsglue.job import Job
# Initialize Glue context
args = getResolvedOptions(sys.argv, ['JOB_NAME'])
sc = SparkContext()
glueContext = GlueContext(sc)
spark = glueContext.spark_session
job = Job(glueContext)
job.init(args['JOB_NAME'], args)
# Read from RDS SQL Server
datasource0 = glueContext.create_dynamic_frame.from_options(
connection_type="sqlserver",
connection_options={
"url": "jdbc:sqlserver://your-rds-endpoint:1433;databaseName=YourDB",
"user": "username",
"password": "password",
"dbtable": "source_table"
}
)
job.commit()
-- Monitor SSRS report execution performance
SELECT
ItemPath,
UserName,
RequestType,
Format,
TimeStart,
TimeEnd,
DATEDIFF(second, TimeStart, TimeEnd) AS DurationSeconds,
ByteCount,
RowCount
FROM ReportServer.dbo.ExecutionLog3
WHERE TimeStart >= DATEADD(day, -7, GETDATE())
ORDER BY DurationSeconds DESC;
VPC Isolation and Subnet Groups Your RDS instances should never be deployed in public subnets. Instead, create dedicated database subnet groups within private subnets of your VPC. This ensures your database instances are not directly accessible from the internet and can only be reached through controlled access points.
-- Example of checking current network configuration
SELECT
name,
value,
value_in_use,
description
FROM sys.configurations
WHERE name LIKE '%network%'
Security Groups as Database Firewalls Configure security groups to act as virtual firewalls, allowing only necessary traffic to reach your RDS instances. Follow the principle of least privilege by restricting access to specific IP ranges, security groups, or application tiers.
IAM Database Authentication Enable IAM database authentication to leverage AWS IAM for database access control. This eliminates the need to store database credentials in your applications and provides centralized access management.
-- Create a database user for IAM authentication
CREATE USER [db_user] FROM EXTERNAL PROVIDER;
ALTER ROLE db_datareader ADD MEMBER [db_user];
Parameter Group Security Settings Configure your RDS parameter group to enforce security best practices:
Encryption at Rest Always enable encryption at rest for production RDS instances. AWS RDS uses AWS KMS (Key Management Service) to encrypt your database instances, automated backups, read replicas, and snapshots.
Encryption in Transit Force SSL connections to ensure all data transmitted between your applications and RDS instances is encrypted. This can be configured at the parameter group level and enforced through connection strings.
-- Verify SSL connection status
SELECT
session_id,
login_name,
host_name,
program_name,
encrypt_option
FROM sys.dm_exec_sessions
WHERE is_user_process = 1;
Unlike on-premises SQL Server instances, AWS RDS restricts access to certain system-level features, including SQL Server Agent jobs. However, there are several effective approaches to implement and monitor scheduled tasks.
AWS Lambda with EventBridge For routine maintenance tasks and data processing jobs, consider using AWS Lambda functions triggered by EventBridge (formerly CloudWatch Events). This serverless approach provides better scalability and integration with other AWS services.
RDS Custom for SQL Server If you require full SQL Server Agent functionality, consider RDS Custom for SQL Server, which provides more administrative control while maintaining the benefits of a managed service.
CloudWatch Metrics Integration AWS RDS automatically publishes database metrics to CloudWatch, providing visibility into:
-- Monitor current database activity
SELECT
r.session_id,
r.status,
r.command,
r.percent_complete,
r.estimated_completion_time,
s.login_name,
s.host_name,
s.program_name
FROM sys.dm_exec_requests r
INNER JOIN sys.dm_exec_sessions s ON r.session_id = s.session_id
WHERE r.session_id > 50;
Enhanced Monitoring and Performance Insights Enable Enhanced Monitoring to get deeper visibility into your RDS instance’s operating system metrics. Performance Insights provides a dashboard for analyzing database load and identifying performance bottlenecks.
Database-Level Job Tracking Create custom tables to track job execution and status:
-- Create a job tracking table
CREATE TABLE JobExecutionLog (
JobID INT IDENTITY(1,1) PRIMARY KEY,
JobName NVARCHAR(255) NOT NULL,
StartTime DATETIME2 DEFAULT GETDATE(),
EndTime DATETIME2 NULL,
Status NVARCHAR(50) DEFAULT 'Running',
ErrorMessage NVARCHAR(MAX) NULL,
ExecutedBy NVARCHAR(255) DEFAULT SYSTEM_USER
);
-- Stored procedure to log job execution
CREATE PROCEDURE sp_LogJobExecution
@JobName NVARCHAR(255),
@Status NVARCHAR(50) = 'Completed',
@ErrorMessage NVARCHAR(MAX) = NULL
AS
BEGIN
IF @Status = 'Started'
BEGIN
INSERT INTO JobExecutionLog (JobName, Status)
VALUES (@JobName, @Status);
END
ELSE
BEGIN
UPDATE JobExecutionLog
SET EndTime = GETDATE(),
Status = @Status,
ErrorMessage = @ErrorMessage
WHERE JobName = @JobName
AND EndTime IS NULL;
END
END;
Integration with AWS SNS for Alerting Set up CloudWatch alarms that trigger AWS SNS notifications when specific conditions are met, such as failed connections, high CPU usage, or custom metrics from your job tracking system.
Enable AWS CloudTrail to log all API calls made to your RDS instances. This provides an audit trail of who made changes to your database configuration, when changes occurred, and from which IP addresses.
-- Enable SQL Server audit for login monitoring
CREATE SERVER AUDIT RDS_Security_Audit
TO FILE (FILEPATH = 'D:\rdsdbdata\Log\')
WITH (
ON_FAILURE = CONTINUE,
AUDIT_GUID = NEWID()
);
CREATE SERVER AUDIT SPECIFICATION RDS_Login_Audit
FOR SERVER AUDIT RDS_Security_Audit
ADD (FAILED_LOGIN_GROUP),
ADD (SUCCESSFUL_LOGIN_GROUP);
ALTER SERVER AUDIT RDS_Security_Audit WITH (STATE = ON);
ALTER SERVER AUDIT SPECIFICATION RDS_Login_Audit WITH (STATE = ON);
Implement automated security assessments using:
Always deploy production RDS instances with Multi-AZ configuration for high availability and automatic failover capabilities.
-- Monitor Multi-AZ status and failover history
SELECT
GETDATE() as CheckTime,
SERVERPROPERTY('ServerName') as CurrentServer,
SERVERPROPERTY('IsClustered') as IsClusteredInstance,
SERVERPROPERTY('IsHadrEnabled') as IsHADREnabled;
-- Check for recent failover events in error log
EXEC xp_readerrorlog 0, 1, N'failover';
-- Query Store analysis for performance optimization
SELECT
qsp.plan_id,
qst.query_sql_text,
qsp.avg_duration/1000.0 as avg_duration_ms,
qsp.avg_cpu_time/1000.0 as avg_cpu_time_ms,
qsp.avg_logical_io_reads,
qsp.execution_count
FROM sys.query_store_plan qsp
INNER JOIN sys.query_store_query qsq ON qsp.query_id = qsq.query_id
INNER JOIN sys.query_store_query_text qst ON qsq.query_text_id = qst.query_text_id
WHERE qsp.avg_duration > 10000 -- Queries taking more than 10ms on average
ORDER BY qsp.avg_duration DESC;
-- Storage usage monitoring
SELECT
database_name,
CAST(SUM(size) * 8.0 / 1024 / 1024 AS DECIMAL(10,2)) AS size_gb,
CAST(SUM(FILEPROPERTY(name, 'SpaceUsed')) * 8.0 / 1024 / 1024 AS DECIMAL(10,2)) AS used_gb,
CAST((SUM(size) - SUM(FILEPROPERTY(name, 'SpaceUsed'))) * 8.0 / 1024 / 1024 AS DECIMAL(10,2)) AS free_gb
FROM sys.master_files mf
INNER JOIN sys.databases d ON mf.database_id = d.database_id
WHERE d.database_id > 4
GROUP BY database_name
ORDER BY size_gb DESC;
Assessment and Planning
Environment Setup
Data Migration
Application Integration
Performance Tuning
Security Hardening
Successfully migrating SQL Server to AWS RDS requires more than just moving data—it demands a comprehensive understanding of cloud-native architectures, security implementations, and operational best practices. The key to success lies in thorough planning, understanding service limitations, and leveraging AWS’s extensive ecosystem of tools and services.
Key Takeaways:
Migration Strategy: Choose the right migration approach (DMS vs. native methods) based on your specific requirements, data size, and downtime tolerance.
Backup and Recovery: Implement a robust backup strategy that combines RDS automated backups with S3 integration for enhanced flexibility and cross-region disaster recovery.
Business Intelligence: Plan for SSIS and SSRS limitations early, considering alternative architectures like EC2-hosted SSIS or cloud-native solutions like AWS Glue.
Security First: Implement comprehensive security measures from day one, including network isolation, encryption, and comprehensive auditing.
Operational Excellence: Establish monitoring, job tracking, and performance optimization processes that account for RDS-specific capabilities and limitations.
The transition to AWS RDS SQL Server opens up new possibilities for scalability, integration, and operational efficiency. However, success requires embracing cloud-native approaches while maintaining the reliability and security standards your business demands.
At InFocus Data, we’ve seen organizations achieve up to 30% reduction in operational costs and significant improvements in scalability and reliability through well-executed RDS migrations. The key is having a partner who understands both the technical complexities and business implications of this transformation.
Ready to make your AWS RDS SQL Server migration a success story? InFocus Data’s expert database administrators and cloud architects can guide you through every step of the process, from initial assessment through post-migration optimization.
InFocus Data, LLC
📧 info@infocusdata.com
📞 (405) 833-5857
We specialize in aligning data strategies with business objectives—turning complex migrations into competitive advantages.