Azure SQL Database → AWS RDS for SQL Server PRODUCTION
Overview & Scope
This runbook covers a live schema-plus-data migration from Azure SQL Database (PaaS) to AWS RDS for SQL Server using MigrationBridge. The same connection profile supports the reverse direction (RDS → Azure SQL) by swapping the Source and Target fields in Step 1.
What This SOP Covers
- Full-copy (bulk insert) migration of all user tables
- Live (Change-Tracking–based) CDC catch-up after full load
- Schema assessment: compatibility blockers, unsupported features
- Post-migration RDS hardening: backup retention, parameter groups, Multi-AZ, CloudWatch alarms
- Data integrity verification (row counts + checksum spot-checks)
What This SOP Does NOT Cover
- SSIS packages, Reporting Services, or Analysis Services objects
- Cross-database views or synonyms (must be recreated manually — see Known Issues)
- Azure SQL features unavailable on RDS: Always Encrypted column keys, Ledger tables, Hyperscale
- DNS cutover / application connection-string changes
Estimated Timelines
| Database Size | Full-Copy Duration | CT Catch-Up | Total Window |
|---|---|---|---|
| < 10 GB | 15 – 45 min | < 5 min | ~1 h |
| 10 – 100 GB | 1 – 4 h | 5 – 30 min | ~5 h |
| 100 GB – 1 TB | 4 – 18 h | 30 min – 2 h | ~20 h |
| > 1 TB | Contact support | Variable | Plan cutover carefully |
Prerequisites — Source (Azure SQL Database)
1. Create a Contained Migration User
Run the following against the source database (not master). Contained users are scoped to the database and do not require a server-level login — the preferred pattern on Azure SQL PaaS.
-- ───────────────────────────────────────────────────────────────────────────── -- Azure SQL: create contained migration user with minimum required permissions -- Run in: source database context (NOT master) -- ───────────────────────────────────────────────────────────────────────────── USE [YourSourceDatabase]; GO -- Create contained user mapped to Azure AD or SQL auth CREATE USER [mb_migration] WITH PASSWORD = N'Str0ng!Pass#2026'; GO -- Minimum read permissions ALTER ROLE [db_datareader] ADD MEMBER [mb_migration]; GO -- Required for assessment queries (blocking, sessions, query stats) GRANT VIEW DATABASE STATE TO [mb_migration]; GO -- Required for Change Tracking (live migration mode only) GRANT VIEW CHANGE TRACKING TO [mb_migration]; GO -- Verify SELECT dp.name, dp.type_desc, drm.role_principal_id FROM sys.database_principals dp LEFT JOIN sys.database_role_members drm ON dp.principal_id = drm.member_principal_id WHERE dp.name = N'mb_migration';
2. Azure SQL Firewall — Allow MigrationBridge Host
In the Azure portal or via Azure CLI, add the public IP of the MigrationBridge host.
# Azure CLI — add server-level firewall rule
az sql server firewall-rule create \
--resource-group <your-rg> \
--server <azure-sql-server-name> \
--name MigrationBridgeHost \
--start-ip-address <mb-host-public-ip> \
--end-ip-address <mb-host-public-ip>
3. Readiness Verification Queries
Run all three checks. All must return expected values before proceeding.
-- ① Connectivity & edition check SELECT SERVERPROPERTY('Edition') AS Edition, SERVERPROPERTY('EngineEdition') AS EngineEdition, -- 5 = Azure SQL DB SERVERPROPERTY('ProductVersion') AS ProductVersion, DB_NAME() AS CurrentDatabase; -- ② Confirm user has required permissions SELECT HAS_PERMS_BY_NAME(DB_NAME(), 'DATABASE', 'VIEW DATABASE STATE') AS has_view_db_state, IS_ROLEMEMBER('db_datareader') AS is_datareader; -- ③ Count user tables eligible for migration SELECT COUNT(*) AS total_user_tables, SUM(p.rows) AS total_rows_approx FROM sys.tables t JOIN sys.partitions p ON t.object_id = p.object_id AND p.index_id IN (0,1) WHERE t.is_ms_shipped = 0; -- ④ Check Change Tracking status (required for live mode) SELECT is_change_tracking_on, retention_period, retention_period_units_desc FROM sys.change_tracking_databases WHERE database_id = DB_ID();
Prerequisites — Target (AWS RDS for SQL Server)
1. Open VPC Security Group — TCP 1433
The RDS instance's Security Group must allow inbound TCP 1433 from the MigrationBridge host IP.
# AWS CLI — authorize inbound TCP 1433 from MigrationBridge host aws ec2 authorize-security-group-ingress \ --group-id <rds-sg-id> \ --protocol tcp \ --port 1433 \ --cidr <mb-host-public-ip>/32 # Verify rule was added aws ec2 describe-security-groups \ --group-ids <rds-sg-id> \ --query 'SecurityGroups[0].IpPermissions'
2. Create SQL Login on RDS
RDS for SQL Server does not support contained users in the same way as Azure SQL PaaS. Create a standard server-level login, then map it to a database user.
-- ───────────────────────────────────────────────────────────────────────────── -- RDS: create server login + database user (NOT a contained user) -- Run as: master admin login (the one created during RDS provisioning) -- ───────────────────────────────────────────────────────────────────────────── -- Step A: create login at server scope USE [master]; GO CREATE LOGIN [mb_migration] WITH PASSWORD = N'Str0ng!Pass#2026', CHECK_POLICY = ON, CHECK_EXPIRATION = OFF; GO -- Step B: map to target database USE [YourTargetDatabase]; GO CREATE USER [mb_migration] FOR LOGIN [mb_migration]; GO -- Step C: grant write + schema access for migration inserts ALTER ROLE [db_datareader] ADD MEMBER [mb_migration]; ALTER ROLE [db_datawriter] ADD MEMBER [mb_migration]; ALTER ROLE [db_ddladmin] ADD MEMBER [mb_migration]; GRANT VIEW DATABASE STATE TO [mb_migration]; GO -- Verify SELECT dp.name, rp.name AS role_name FROM sys.database_role_members drm JOIN sys.database_principals dp ON drm.member_principal_id = dp.principal_id JOIN sys.database_principals rp ON drm.role_principal_id = rp.principal_id WHERE dp.name = N'mb_migration';
3. Test Connectivity from MigrationBridge Host
# PowerShell — test TCP 1433 reachability to RDS endpoint Test-NetConnection -ComputerName <rds-endpoint>.rds.amazonaws.com ` -Port 1433 -InformationLevel Detailed # Also test Azure SQL endpoint Test-NetConnection -ComputerName <server>.database.windows.net ` -Port 1433 -InformationLevel Detailed
4. RDS Instance Checklist
| Item | Requirement | Status |
|---|---|---|
| SQL Server Edition | SE or EE (Express does not support CT) | Verify |
| SQL Server Version | 2017 or later recommended | Verify |
| Storage (gp3) | ≥ 1.2× source database size | Check |
| Multi-AZ | Recommended for prod; enable after migration | Post-Migration |
| Backup Retention | Minimum 7 days; 35 days for prod | Post-Migration |
| VPC Security Group | TCP 1433 open from MB host | Action Required |
| Parameter Group | Custom group for tuning (post-migration) | Post-Migration |
Connect to Source and Target
Enter connection details for both databases. MigrationBridge tests both connections before allowing you to proceed to assessment. All credentials are encrypted in memory and never written to disk.
Schema & Compatibility Assessment
MigrationBridge interrogates both engines and flags objects that require manual remediation before or after migration. Resolve all Blocker items before proceeding to Step 3.
| Category | Finding | Severity | Action |
|---|---|---|---|
| Cross-Database References | 4 views reference OtherDB.dbo.* (3-part names) |
Blocker | Recreate as local views or use synonyms on RDS after DB is in place |
| Linked Servers | 1 linked server definition (AZURESQL_REPORTING) |
Blocker | Linked servers cannot be migrated; reconfigure manually on RDS |
| SQL Agent Jobs | 7 Agent jobs detected in msdb |
Warning | Azure SQL does not expose Agent; export from on-prem or script manually |
| FILESTREAM / FileTable | Not detected | Pass | No action required |
| CLR Assemblies | 2 SAFE assemblies detected (StringUtils, GeoHelpers) |
Warning | RDS supports CLR with clr enabled; deploy DLL to RDS and re-register |
| Temporal Tables (SysEnd) | 3 temporal tables with GENERATED ALWAYS AS ROW END columns |
Warning | Temporal tables must be versioned-off before bulk insert; re-enable after. See Known Issues. |
| Change Tracking Readiness | CT not yet enabled on source database | Warning | Enable CT before starting migration if live mode is desired. See CT Setup. |
| Full-Text Catalogs | 1 full-text catalog (FT_EndriasBridgeWH) with 2 indexes |
Warning | Full-text catalogs must be created and populated manually on RDS after migration |
| Deprecated Data Types | text (6 cols), ntext (2 cols), image (1 col), timestamp (3 cols) |
Advisory | MigrationBridge will auto-upgrade to varchar(max) / varbinary(max) / rowversion. Confirm in Type Conversions. |
| Encrypted Columns (AE) | Not detected | Pass | No action required |
| Ledger Tables | Not detected | Pass | No action required |
| Row-Level Security | 2 security policies detected | Advisory | RLS policies will be scripted and applied on target; verify predicate functions exist |
| Schema Count | 6 user schemas | Pass | All schemas will be created on target before table migration |
Assessment SQL — Run Manually for Cross-DB References
-- Find views and procedures with 3-part (cross-database) object references SELECT o.type_desc AS ObjectType, o.name AS ObjectName, sm.definition FROM sys.sql_modules sm JOIN sys.objects o ON sm.object_id = o.object_id WHERE sm.definition LIKE '%[DatabaseName]%.%' -- replace [DatabaseName] OR sm.definition LIKE '%].dbo.[%' ORDER BY o.type_desc, o.name;
Select Tables & Migration Mode
Choose which tables to include and select the migration mode. Full Copy performs a complete bulk-insert of all rows. Incremental (CT) applies only changes since the last sync version (requires Change Tracking). Schema Only creates tables without migrating data.
Migration Mode
Table Selection (9 of 47 shown)
| Schema.Table | Row Count | Data Size | Has CT | Temporal | Status | |
|---|---|---|---|---|---|---|
dbo.BgClaim |
4,812,330 | 2.1 GB | Yes | No | Ready | |
dbo.BgMember |
1,203,450 | 620 MB | Yes | No | Ready | |
dbo.BgProvider |
89,200 | 48 MB | Yes | No | Ready | |
hist.BgClaimHistory |
22,471,000 | 9.4 GB | No | Yes | Needs Prep | |
ref.DrugFormulary |
342,000 | 88 MB | Yes | No | Ready | |
ref.ICD10Codes |
94,500 | 24 MB | No | No | Ready | |
audit.AccessLog |
67,200,000 | 18.2 GB | No | No | Ready | |
dbo.BgAuthorization |
5,620,800 | 3.3 GB | Yes | No | Ready | |
cfg.SystemConfig |
1,240 | 0.8 MB | No | No | Ready |
47 total tables · 47 selected · 1 requires temporal prep · Estimated total: 33.8 GB
hist.BgClaimHistory (and 2 other temporal tables) must have system-versioning disabled before
the bulk insert, then re-enabled after. MigrationBridge will do this automatically when Full Copy mode is
selected — confirm the checkbox in the options panel before starting.
Run Migration & Monitor Progress
Click Start Migration to begin the full-copy transfer. MigrationBridge streams rows in
configurable batches (default 10,000) using SqlBulkCopy with table-lock hints for maximum
throughput. Do not close the application during migration.
Live Log Panel
Monitor from CLI (Headless)
# PowerShell — tail the MigrationBridge log file in real time Get-Content -Path "C:\MigrationT\Migrationtool\Output\migration_$(Get-Date -f yyyyMMdd).log" ` -Wait -Tail 20
Verify Data Integrity
After migration completes, run the row-count spot-check and optional checksum verification to confirm data fidelity. Do not perform cutover until all critical tables pass verification.
Row Count Spot-Check — Source (Azure SQL)
-- Run on SOURCE (Azure SQL Database) SELECT QUOTENAME(SCHEMA_NAME(t.schema_id)) + '.' + QUOTENAME(t.name) AS TableName, SUM(p.rows) AS RowCount_Source, SUM(a.total_pages) * 8 / 1024.0 AS SizeMB_Source FROM sys.tables t JOIN sys.partitions p ON t.object_id = p.object_id AND p.index_id IN (0,1) JOIN sys.allocation_units a ON p.partition_id = a.container_id WHERE t.is_ms_shipped = 0 GROUP BY t.schema_id, t.name ORDER BY SUM(p.rows) DESC;
Row Count Spot-Check — Target (RDS)
-- Run on TARGET (AWS RDS for SQL Server) — identical query SELECT QUOTENAME(SCHEMA_NAME(t.schema_id)) + '.' + QUOTENAME(t.name) AS TableName, SUM(p.rows) AS RowCount_Target, SUM(a.total_pages) * 8 / 1024.0 AS SizeMB_Target FROM sys.tables t JOIN sys.partitions p ON t.object_id = p.object_id AND p.index_id IN (0,1) JOIN sys.allocation_units a ON p.partition_id = a.container_id WHERE t.is_ms_shipped = 0 GROUP BY t.schema_id, t.name ORDER BY SUM(p.rows) DESC;
Checksum Verification (Critical Tables)
-- Compute checksum for a critical table — run on BOTH source and target -- Results must match exactly SELECT COUNT(*) AS RowCount, CHECKSUM_AGG(BINARY_CHECKSUM(*)) AS TableChecksum FROM dbo.BgClaim; -- For large tables: checksum a representative sample SELECT CHECKSUM_AGG(BINARY_CHECKSUM(ClaimId, MemberId, ClaimDate, TotalAmount, StatusCode)) AS SampleChecksum FROM ( SELECT TOP 100000 ClaimId, MemberId, ClaimDate, TotalAmount, StatusCode FROM dbo.BgClaim ORDER BY ClaimId ) s;
Verification Results
| Table | Source Rows | Target Rows | Match | Checksum |
|---|---|---|---|---|
dbo.BgClaim |
4,812,330 | 4,812,330 | Pass | Match |
dbo.BgMember |
1,203,450 | 1,203,450 | Pass | Match |
dbo.BgProvider |
89,200 | 89,200 | Pass | Match |
hist.BgClaimHistory |
22,471,000 | 22,471,000 | Pass | Match |
audit.AccessLog |
67,200,000 | 67,200,000 | Pass | Match |
dbo.BgAuthorization |
5,620,800 | 5,620,800 | Pass | Match |
ref.DrugFormulary |
342,000 | 342,000 | Pass | Match |
Post-Migration RDS Hardening
After successful verification, harden the RDS instance for production: extend backup retention, tune the parameter group, enable Multi-AZ, and configure CloudWatch alarms.
1. Extend Automated Backup Retention to 35 Days
# AWS CLI — extend backup retention for PITR coverage aws rds modify-db-instance \ --db-instance-identifier acmecorp-rds \ --backup-retention-period 35 \ --apply-immediately # Verify new retention setting aws rds describe-db-instances \ --db-instance-identifier acmecorp-rds \ --query 'DBInstances[0].BackupRetentionPeriod'
2. Custom Parameter Group — SQL Server Tuning
# Step A: create custom parameter group aws rds create-db-parameter-group \ --db-parameter-group-name acmecorp-sqlserver-2019-pg \ --db-parameter-group-family sqlserver-se-15.0 \ --description "Acme Corp production tuning — SQL Server 2019 SE" # Step B: set cost threshold for parallelism (default 5 is too low for OLAP) aws rds modify-db-parameter-group \ --db-parameter-group-name acmecorp-sqlserver-2019-pg \ --parameters \ ParameterName="cost threshold for parallelism",ParameterValue="50",ApplyMethod="immediate" # Step C: cap max degree of parallelism (8 vCPU instance) aws rds modify-db-parameter-group \ --db-parameter-group-name acmecorp-sqlserver-2019-pg \ --parameters \ ParameterName="max degree of parallelism",ParameterValue="4",ApplyMethod="immediate" # Step D: attach parameter group to instance aws rds modify-db-instance \ --db-instance-identifier acmecorp-rds \ --db-parameter-group-name acmecorp-sqlserver-2019-pg \ --apply-immediately # Step E: verify parameters applied aws rds describe-db-parameters \ --db-parameter-group-name acmecorp-sqlserver-2019-pg \ --query "Parameters[?ParameterName=='cost threshold for parallelism' || ParameterName=='max degree of parallelism']"
3. Enable Multi-AZ Standby
# Enable Multi-AZ (synchronous standby in secondary AZ) # NOTE: This triggers a brief failover (~60s) during the conversion window aws rds modify-db-instance \ --db-instance-identifier acmecorp-rds \ --multi-az \ --apply-immediately # Monitor status until "available" aws rds describe-db-instances \ --db-instance-identifier acmecorp-rds \ --query 'DBInstances[0].{Status:DBInstanceStatus,MultiAZ:MultiAZ}'
4. CloudWatch Alarms — Three Critical Metrics
# Alarm 1: High CPU Utilization (> 80% for 5 consecutive minutes) aws cloudwatch put-metric-alarm \ --alarm-name "acmecorp-rds-cpu-high" \ --alarm-description "RDS SQL Server CPU > 80% for 5 min" \ --metric-name CPUUtilization \ --namespace AWS/RDS \ --statistic Average \ --period 60 \ --evaluation-periods 5 \ --threshold 80 \ --comparison-operator GreaterThanThreshold \ --dimensions Name=DBInstanceIdentifier,Value=acmecorp-rds \ --alarm-actions arn:aws:sns:us-east-1:<account-id>:dba-alerts \ --ok-actions arn:aws:sns:us-east-1:<account-id>:dba-alerts # Alarm 2: Low Free Storage (< 20 GB) aws cloudwatch put-metric-alarm \ --alarm-name "acmecorp-rds-storage-low" \ --alarm-description "RDS SQL Server free storage < 20 GB" \ --metric-name FreeStorageSpace \ --namespace AWS/RDS \ --statistic Average \ --period 300 \ --evaluation-periods 3 \ --threshold 21474836480 \ --comparison-operator LessThanThreshold \ --dimensions Name=DBInstanceIdentifier,Value=acmecorp-rds \ --alarm-actions arn:aws:sns:us-east-1:<account-id>:dba-alerts # Alarm 3: High Connection Count (> 450 connections) aws cloudwatch put-metric-alarm \ --alarm-name "acmecorp-rds-connections-high" \ --alarm-description "RDS SQL Server connection count > 450" \ --metric-name DatabaseConnections \ --namespace AWS/RDS \ --statistic Average \ --period 60 \ --evaluation-periods 3 \ --threshold 450 \ --comparison-operator GreaterThanThreshold \ --dimensions Name=DBInstanceIdentifier,Value=acmecorp-rds \ --alarm-actions arn:aws:sns:us-east-1:<account-id>:dba-alerts # Verify all three alarms aws cloudwatch describe-alarms \ --alarm-name-prefix "acmecorp-rds-" \ --query 'MetricAlarms[].{Name:AlarmName,State:StateValue}'
- Backup retention extended to 35 days
- Custom parameter group applied (CTFP=50, MAXDOP=4)
- Multi-AZ enabled (or scheduled)
- Three CloudWatch alarms active (CPU, Storage, Connections)
- Security group reviewed — remove MB host IP if no longer needed
- Application connection strings updated to RDS endpoint
Change Tracking Setup (Live Migration)
Change Tracking (CT) enables MigrationBridge to apply row-level changes (INSERT / UPDATE / DELETE) that occurred on the source during the full-copy phase, minimizing the cutover window. The sequence is: enable CT → start full copy → after full copy, apply CT delta → cutover.
Step A — Enable CT on the Source Database
-- Run on SOURCE (Azure SQL Database) — in source database context USE [EndriasBridgeWH]; GO ALTER DATABASE [EndriasBridgeWH] SET CHANGE_TRACKING = ON (CHANGE_RETENTION = 30 DAYS, AUTO_CLEANUP = ON); GO
Step B — Enable CT on Each Table
-- Enable CT on all user tables (run once per table; adjust schema/name) ALTER TABLE dbo.BgClaim ENABLE CHANGE_TRACKING WITH (TRACK_COLUMNS_UPDATED = ON); ALTER TABLE dbo.BgMember ENABLE CHANGE_TRACKING WITH (TRACK_COLUMNS_UPDATED = ON); ALTER TABLE dbo.BgProvider ENABLE CHANGE_TRACKING WITH (TRACK_COLUMNS_UPDATED = ON); ALTER TABLE dbo.BgAuthorization ENABLE CHANGE_TRACKING WITH (TRACK_COLUMNS_UPDATED = ON); ALTER TABLE ref.DrugFormulary ENABLE CHANGE_TRACKING WITH (TRACK_COLUMNS_UPDATED = ON); -- Repeat for all tables requiring live sync (not needed for static reference tables)
Step C — Grant VIEW CHANGE TRACKING to Migration User
-- Grant the migration user access to read change tracking data GRANT VIEW CHANGE TRACKING ON SCHEMA::dbo TO [mb_migration]; GRANT VIEW CHANGE TRACKING ON SCHEMA::ref TO [mb_migration]; GRANT VIEW CHANGE TRACKING ON SCHEMA::hist TO [mb_migration]; GRANT VIEW CHANGE TRACKING ON SCHEMA::audit TO [mb_migration]; GRANT VIEW CHANGE TRACKING ON SCHEMA::cfg TO [mb_migration];
Step D — Validate CT State
-- Confirm CT is active on database SELECT d.name AS DatabaseName, ct.is_change_tracking_on, ct.retention_period, ct.retention_period_units_desc, ct.is_auto_cleanup_on, CHANGE_TRACKING_CURRENT_VERSION() AS CurrentVersion FROM sys.databases d JOIN sys.change_tracking_databases ct ON d.database_id = ct.database_id WHERE d.name = DB_NAME(); -- Confirm CT is enabled on specific tables SELECT SCHEMA_NAME(t.schema_id) + '.' + t.name AS TableName, ct.is_track_columns_updated_on, ct.min_valid_version FROM sys.tables t JOIN sys.change_tracking_tables ct ON t.object_id = ct.object_id ORDER BY t.name;
UI Busy / Unresponsive During Migration
During large table transfers (tens of millions of rows), the MigrationBridge UI may become temporarily unresponsive as the worker threads are CPU- and I/O-bound. This is expected behavior and does not indicate a crash or hang.
Symptoms
- Progress bar appears frozen for 1–5 minutes
- Windows reports "Not Responding" in the title bar
- Log panel stops scrolling
- Throughput tiles show stale values
Recommended Actions
- Wait at least 5 minutes before concluding the application is hung
- Check the log file directly — if it is still being written, migration is running normally
- Check Task Manager: if
migrationbridge.exeCPU is above 20%, transfer is active - Do NOT close or force-terminate the process — this will interrupt the current table transfer
- If the log file has not changed for > 15 minutes AND CPU is at 0%, the process may be deadlocked — see below
Headless CLI Tip — Run Without the UI
For very large migrations, run MigrationBridge in headless mode from a terminal to avoid UI overhead entirely. All progress is written to the log file and can be monitored with PowerShell.
# Launch MigrationBridge in headless mode using a saved profile python "C:\MigrationT\Migrationtool\launch_gui.pyw" --headless --profile EndriasBridgeWH_AzureToRDS.json # Monitor progress in real time Get-Content -Path "C:\MigrationT\Migrationtool\Output\migration_$(Get-Date -f yyyyMMdd).log" ` -Wait -Tail 20 # Check for errors only Select-String -Path "C:\MigrationT\Migrationtool\Output\*.log" -Pattern "ERROR|FAIL"
If the Process Is Truly Hung
# PowerShell — check if MigrationBridge has an open SQL connection
Get-Process migrationbridge | Select-Object Name, CPU, WorkingSet64, Responding
-- T-SQL on target RDS — check for blocking sessions SELECT r.session_id, r.blocking_session_id, r.command, r.status, r.wait_type, r.wait_time / 1000.0 AS wait_sec, SUBSTRING(st.text, r.statement_start_offset / 2 + 1, (CASE r.statement_end_offset WHEN -1 THEN LEN(CONVERT(nvarchar(max), st.text)) * 2 ELSE r.statement_end_offset END - r.statement_start_offset) / 2 ) AS CurrentStatement FROM sys.dm_exec_requests r CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) st WHERE r.session_id > 50 -- exclude system sessions ORDER BY r.blocking_session_id DESC;
Known Issues & Limitations
| Issue | Affected Feature | Severity | Workaround |
|---|---|---|---|
| Temporal table SysEnd column incompatibility | System-versioned temporal tables | Warning | MigrationBridge automatically disables system-versioning before bulk insert and re-enables after.
Verify via sys.tables WHERE temporal_type = 2 on target post-migration. |
| Cross-database object references fail | Views, procedures with 3-part names | Blocker | Drop or rewrite affected objects to use local names. After all databases are on RDS, recreate cross-DB references using linked server or synonyms. |
| SQL Agent Jobs not migrated | msdb SQL Agent jobs | Warning | Script jobs from source using SSMS → SQL Server Agent → Jobs → Script. Apply on RDS target after migration. Adjust job step connection strings. |
| Linked server definitions dropped | sys.servers linked server rows | Blocker | Recreate linked servers on RDS manually using sp_addlinkedserver after all target
databases are live. Update all dependent objects. |
| CLR assemblies require manual re-registration | CLR stored procedures / functions | Warning | Enable CLR on RDS: set parameter clr enabled = 1 in parameter group. Upload DLL
to S3, download to EC2 in same VPC, then run CREATE ASSEMBLY from local path. |
| TCP 10054 / connection reset mid-transfer | Large table bulk inserts over cross-cloud TCP | Warning | Azure SQL and RDS have idle connection timeouts (~30 min). MigrationBridge reconnects automatically and resumes from the last committed batch. If persistent, reduce batch size to 1,000 and enable keep-alive in the connection string. |
| Multi-AZ failover interrupts in-flight transfer | RDS Multi-AZ automatic failover | Warning | If an unplanned Multi-AZ failover occurs during migration, MigrationBridge will reconnect and resume from the last committed batch. Monitor the log for reconnect events. Re-run verification after migration completes. |
| Full-text catalogs not migrated | Full-text search indexes and catalogs | Advisory | MigrationBridge migrates table data only — not full-text catalogs. After migration, run
CREATE FULLTEXT CATALOG, CREATE FULLTEXT INDEX, and allow population to
complete before enabling full-text queries. |
Data Type Conversions — Azure SQL → RDS
Azure SQL Database and AWS RDS for SQL Server are both SQL Server engines; the vast majority of data types are identical. The table below documents 1:1 pass-throughs and the auto-upgrades applied by MigrationBridge for deprecated types.
| Source Type (Azure SQL) | Target Type (RDS) | Conversion | Notes |
|---|---|---|---|
int | int | 1:1 | No change |
bigint | bigint | 1:1 | No change |
smallint | smallint | 1:1 | No change |
tinyint | tinyint | 1:1 | No change |
decimal(p,s) | decimal(p,s) | 1:1 | Precision and scale preserved exactly |
numeric(p,s) | numeric(p,s) | 1:1 | No change |
float | float | 1:1 | No change; IEEE 754 double precision |
real | real | 1:1 | No change; IEEE 754 single precision |
money | money | 1:1 | No change |
smallmoney | smallmoney | 1:1 | No change |
bit | bit | 1:1 | No change |
char(n) | char(n) | 1:1 | No change; collation inherited from DB default |
nchar(n) | nchar(n) | 1:1 | No change; Unicode fixed-width |
varchar(n) | varchar(n) | 1:1 | No change |
varchar(max) | varchar(max) | 1:1 | No change |
nvarchar(n) | nvarchar(n) | 1:1 | No change |
nvarchar(max) | nvarchar(max) | 1:1 | No change |
binary(n) | binary(n) | 1:1 | No change |
varbinary(n) | varbinary(n) | 1:1 | No change |
varbinary(max) | varbinary(max) | 1:1 | No change |
date | date | 1:1 | No change |
time(n) | time(n) | 1:1 | No change; fractional precision preserved |
datetime | datetime | 1:1 | No change; legacy 3.33 ms precision |
datetime2(n) | datetime2(n) | 1:1 | No change; 100 ns precision |
smalldatetime | smalldatetime | 1:1 | No change |
datetimeoffset(n) | datetimeoffset(n) | 1:1 | No change; time zone offset preserved |
uniqueidentifier | uniqueidentifier | 1:1 | No change; GUID/UUID |
xml | xml | 1:1 | XML schema collections migrated separately |
hierarchyid | hierarchyid | 1:1 | No change; CLR type supported on RDS |
geography | geography | 1:1 | Spatial CLR types supported on RDS SE/EE |
geometry | geometry | 1:1 | Spatial CLR types supported on RDS SE/EE |
sql_variant | sql_variant | 1:1 | No change; verify consuming application handles variant correctly |
timestamp Deprecated |
rowversion |
Auto-Upgrade | SQL Server timestamp is a synonym for rowversion; values are 8-byte binary counters, not datetime values. Upgraded to canonical name. |
ntext Deprecated |
nvarchar(max) |
Auto-Upgrade | Unicode LOB storage. No data loss. Update any application code using UPDATETEXT, WRITETEXT, READTEXT — these do not work with nvarchar(max). |
text Deprecated |
varchar(max) |
Auto-Upgrade | ANSI/DBCS LOB storage. No data loss. Same application code caveat as ntext. |
image Deprecated |
varbinary(max) |
Auto-Upgrade | Binary LOB storage. No data loss. Application code using UPDATETEXT / READTEXT must be updated. |
SQL_Latin1_General_CP1_CI_AS unless a custom collation was
specified during database creation. AWS RDS defaults to the collation of the SQL Server installation
(typically SQL_Latin1_General_CP1_CI_AS on US-region instances). MigrationBridge preserves
column-level collation from source. Verify database-level collation matches if you use case-sensitive
collation-dependent queries.