powershelldba.de · Uwe Janke

Migrating SQL Server to Azure: A Step-by-Step Guide

A SQL Server migration to Azure is mostly not about moving bytes. It is about choosing the right target, finding the blockers before they find you, moving everything that lives outside the database, and having a cutover and a rollback plan you have actually rehearsed. Here is the whole process in ten steps, with the tools Microsoft supports today.

Many older guides are out of date. The Data Migration Assistant (DMA) was retired on July 16, 2025, and the Azure SQL Migration extension for Azure Data Studio was retired by February 28, 2026. Assessment now starts in SSMS 22 (or in Azure Arc), and data movement uses Azure Database Migration Service, the Managed Instance link, Log Replay Service or native backup and restore.

Step 1: Choose the Target Platform

"Azure" means three different targets for SQL Server, and the choice drives everything that follows:

TargetWhat it isChoose it when
SQL Server on Azure VM (IaaS) Your SQL Server, on a Windows or Linux VM in Azure. Full control over OS and instance. Lift and shift with zero application changes, features that PaaS does not offer (SSIS/SSRS on the same box, specific versions, OS access, third-party agents).
Azure SQL Managed Instance (PaaS) A managed SQL Server instance: near-complete engine compatibility, SQL Agent, cross-database queries, CLR, linked servers. Patching, backups and HA are handled by Azure. Instance-level features are needed, but you want to stop running OS, patching and HA yourself.
Azure SQL Database (PaaS) A single managed database (or elastic pool). No instance, no SQL Agent, no cross-database queries. New or modernized applications that use one database each, and can live without instance-level features.

Rule of thumb: the closer to "my application expects a full SQL Server instance", the more it points to a VM or Managed Instance. The assessment in step 3 confirms or corrects this choice.

Step 2: Inventory and Baseline

Before any tool runs, know what you are moving. Per instance: versions and editions, all databases with size and growth, collation, compatibility level, encryption (TDE), features in use, and every dependency outside the database: logins, SQL Agent jobs, linked servers, credentials, Database Mail, SSIS packages, server triggers, and the applications and services that connect.

# Quick inventory with dbatools
Get-DbaInstanceProperty -SqlInstance SQL01 |
    Where-Object Name -in 'VersionString','Edition','Collation','IsHadrEnabled'

Get-DbaDatabase -SqlInstance SQL01 -ExcludeSystem |
    Select-Object Name, SizeMB, Compatibility, Collation, RecoveryModel, EncryptionEnabled

Get-DbaAgentJob -SqlInstance SQL01 | Select-Object Name, Enabled, OwnerLoginName
Get-DbaLinkedServer -SqlInstance SQL01 | Select-Object Name, DataSource

Also capture a performance baseline under real load: CPU, memory, IOPS, throughput, latency, top queries, and the peak times. Without it, nobody can later answer "is it slower in Azure?", and sizing becomes guesswork.

Step 3: Assess Compatibility and Size

The current Microsoft tool is the Migrate SQL Server feature in SSMS 22 or later:

  1. In the Visual Studio Installer, modify your SSMS installation and add the Hybrid and Migration workload.
  2. Connect to the source instance, right-click it in Object Explorer and select Migrate SQL Server.
  3. Select Run Assessment and open the generated HTML report.

The report compares Azure SQL Database, Managed Instance and SQL Server on Azure VM, and shows readiness per target, compatibility findings with affected objects, a recommended minimum configuration (tier, vCores, storage) and estimated monthly cost. Treat "Ready with conditions" as a to-do list, not as approval. If the instance is enabled by Azure Arc, SSMS uses the precomputed Arc assessment instead (View Readiness Assessment), and for whole datacenters, Azure Migrate runs the same kind of assessment at scale.

For the assessment alone, the login does not need sysadmin; Microsoft documents a minimum permission set (VIEW SERVER STATE, VIEW ANY DEFINITION, read access to parts of msdb and others). Running the migration from SSMS requires sysadmin.

The sizing is a minimum, not a recommendation for production. Validate it against the baseline from step 2, add headroom for growth, and remember that on a VM, storage throughput and IOPS limits of the VM size often matter more than vCores.

Step 4: Choose the Migration Method

MethodTargetsDowntimeNotes
Backup to URL / restore VM, Managed Instance Moderate to high Simplest path. Downtime = time for final backup, copy and restore. On a VM you can restore full plus log backups WITH NORECOVERY to shrink the window.
Managed Instance link Managed Instance Minimal Uses distributed availability group technology to replicate continuously. The target is readable during the migration; cutover is a planned failover.
Log Replay Service (LRS) Managed Instance Low Restores your full, differential and log backups from Blob Storage continuously. Maximum 30 days per job; the database is not readable on the target until cutover.
Azure Database Migration Service All three Offline or online, depending on target Orchestration from the Azure portal, useful for many databases. Needs a self-hosted integration runtime if backups sit on an on-premises share.
Distributed availability group or log shipping VM Minimal For large databases with near-zero downtime. See Zero-Downtime Migration with Distributed AGs.
SqlPackage (BACPAC) / DMS offline Azure SQL Database High Azure SQL Database cannot restore native .bak files. Schema and data move as BACPAC or via DMS.

Step 5: Prepare the Target and the Network

Step 6: Move Everything Outside the Database

This is the step that decides whether the application works on Monday. Backup/restore and every replication-based method move user databases only. System databases cannot be restored to a Managed Instance, and on a VM you should not try either. Script and recreate:

# Script instance-level objects for review and replay
Export-DbaLogin    -SqlInstance SQL01 -Path C:\Migration\SQL01
Export-DbaInstance -SqlInstance SQL01 -Path C:\Migration\SQL01 -Exclude Databases

On a Managed Instance, logins and jobs are not synchronized automatically after the migration either, which matters if you later add a failover group: Are Logins and SQL Agent Jobs Automatically Synchronized?

Step 7: Do a Test Migration

Run the complete process once with a copy of production, end to end, including the instance-level objects. Then:

Step 8: Migrate the Data

Option A: backup to URL and restore (VM or Managed Instance)

-- On the source (SQL Server 2016+): credential for the container
CREATE CREDENTIAL [https://migstore.blob.core.windows.net/sales]
WITH IDENTITY = 'SHARED ACCESS SIGNATURE',
     SECRET   = '<SAS token without the leading ?>';

BACKUP DATABASE Sales
TO URL = 'https://migstore.blob.core.windows.net/sales/Sales_full.bak'
WITH COMPRESSION, CHECKSUM, STATS = 10;

-- On the target: same credential, then restore
RESTORE DATABASE Sales
FROM URL = 'https://migstore.blob.core.windows.net/sales/Sales_full.bak';

On a VM, restore the full backup WITH NORECOVERY, keep applying log backups, and at cutover restore the tail-log backup WITH RECOVERY: the downtime then shrinks to the last log backup. On a Managed Instance, a manual NORECOVERY restore is not possible; for full plus differential plus log chains use LRS.

Option B: Log Replay Service (Managed Instance)

Put all backups of one database into one flat folder per database in the container (no subfolders), take them WITH CHECKSUM, and start LRS:

# Continuous mode: LRS keeps restoring new backups until you complete it
Start-AzSqlInstanceDatabaseLogReplay -ResourceGroupName 'rg-sql' `
    -InstanceName 'mi-prod-01' -Name 'Sales' `
    -Collation 'SQL_Latin1_General_CP1_CI_AS' `
    -StorageContainerUri 'https://migstore.blob.core.windows.net/migration/Sales' `
    -StorageContainerSasToken '<SAS token with read and list>'

# Progress
Get-AzSqlInstanceDatabaseLogReplay -ResourceGroupName 'rg-sql' -InstanceName 'mi-prod-01' -Name 'Sales'

# Cutover, after the tail-log backup is in the folder and restored
Complete-AzSqlInstanceDatabaseLogReplay -ResourceGroupName 'rg-sql' `
    -InstanceName 'mi-prod-01' -Name 'Sales' -LastBackupName 'Sales_taillog.trn'

With -AutoCompleteRestore -LastBackupName ... on the start command, LRS completes on its own after that file is restored. Plan within the 30-day limit per job. For SQL Server 2019 and later, Microsoft recommends having accelerated database recovery enabled on the source with the persistent version store on PRIMARY.

Option C: Managed Instance link

Configure the link with the SSMS wizard (or scripts), let it seed and synchronize, validate on the readable target, and at cutover fail over the link. Of all the options, it gives you the longest possible migration window with minimal downtime, because the target can be used read-only for validation while replication runs.

Option D: Azure Database Migration Service

In the Azure portal, create or open a DMS instance, select Start migration, pick source and target type, the backup location and the migration mode, and monitor the migration in the DMS dashboard. Use it when you migrate many databases and want one place to orchestrate and monitor them.

Step 9: Cut Over

Write the cutover as a runbook with times, owners and a go/no-go decision point, and rehearse it in step 7. The core sequence:

  1. Stop the workload. Applications, jobs, interfaces, ETL. Disable SQL Agent jobs on the source so nothing writes after the final backup.
  2. Take the tail-log backup (or let the link / LRS / DMS apply the last changes) and confirm the target is fully caught up.
  3. Bring the target online: restore WITH RECOVERY, complete LRS, fail over the link, or select Complete cutover in DMS.
  4. Validate with the queries from step 7: row counts, checksums, business totals.
  5. Switch the connections: connection strings, DSNs, configuration files, or a DNS alias if you prepared one (see DNS Aliases for SQL Server for the caching caveats).
  6. Enable jobs on the target, start the applications, smoke test.
  7. Set the source to read-only (or offline) so no one accidentally keeps writing to it.
Decide the rollback point before you start. Up to the moment applications write to Azure, rollback is simple: point everything back to the untouched source. After that, changes made in Azure are lost on rollback unless you have a way back (for example, the Managed Instance link supports failing back to SQL Server 2022 and later). Agree in advance until when a rollback is allowed and who decides.

Step 10: After the Migration

Checklist

The Bottom Line

A successful Azure migration is decided before the first byte moves: choose the target deliberately, assess with the current tools (SSMS 22 or Azure Arc, not the retired DMA), move logins, jobs and everything else that lives outside the database, and rehearse the full run once with real durations. Then the migration itself is a backup and restore, a link failover or a completed LRS job, and the cutover is a runbook you have already executed.

Sources

← Back to Blog