sql server hub / upgrade guide

SQL Serverupgrade planning guide

A SQL Server upgrade is not just setup. The plan has to cover the supported path, compatibility behavior, dependencies, rollback, and post-upgrade validation.

Use this guide when planning an engine upgrade, edition change, side-by-side upgrade, old-version move, or compatibility-level change.

Guide

Guide~10 min readUpdated 19 Apr 2026

Share

LinkedInXEmail
  1. 01What to validate before a SQL Server upgrade
  2. 02SQL Server upgrade path and supported version checks
  3. 03Choosing a SQL Server upgrade method
  4. 04SQL Server upgrade planning for compatibility levels
  5. 05SQL Server upgrade assessment for deprecated and removed features
  6. 06SQL Server upgrade dependency checks
  7. 07SQL Server upgrade backup, restore, and rollback testing
  8. 08SQL Server upgrade validation after cutover
  9. 09SQL Server upgrade rollback and go/no-go criteria
  10. 10What not to change during SQL Server upgrade planning
  11. 11When SQL Server upgrade planning needs support

What to validate before a SQL Server upgrade

A finished installer does not mean the upgrade is ready for users. The target version has to be supported, the operating system has to be acceptable, databases have to open cleanly, and important queries still need acceptable plans.

Treat edition and feature checks, compatibility level, drivers, linked servers, Query Store, SQL Agent jobs, backups, monitoring, rollback, and application workflows as part of the upgrade. If those checks are skipped, the instance can be online while the service is still broken.

LayerWhat it answers
Version pathWhether the current instance can move to the target version, edition, and platform directly.
Database behaviorWhether compatibility level, plans, and database scoped settings are understood.
DependenciesWhether jobs, linked servers, credentials, drivers, and applications still work.
RollbackWhether the return path is tested inside the real outage window.
Post-upgrade checksWhether jobs, monitoring, Query Store, waits, errors, and application smoke tests are clean.

SQL Server upgrade path and supported version checks

Start with the exact source version. Edition, build, product level, operating system, installed features, and target version decide whether this is an in-place upgrade, side-by-side upgrade, migration, or rebuild.

Check Microsoft supported-version and edition tables before selecting the method. SQL Server 2025 and SQL Server 2022 upgrade paths still depend on the current source version, edition, operating system support, pending reboot state, Windows Installer health, and feature availability.

Target versionDirect setup upgrade sources
SQL Server 2025 (17.x)SQL Server 2014 SP3 or later, SQL Server 2016 SP3 or later, SQL Server 2017, SQL Server 2019, and SQL Server 2022.
SQL Server 2022 (16.x)SQL Server 2012 SP4 or later, SQL Server 2014 SP3 or later, SQL Server 2016 SP3 or later, SQL Server 2017, and SQL Server 2019.
SQL Server 2019 (15.x)SQL Server 2012 SP4 or later, SQL Server 2014 SP2 or later, SQL Server 2016 RTM or later, and SQL Server 2017.
Older or unsupported sourceUsually not a direct setup upgrade to the newest version. Plan a migration, side-by-side move, or intermediate step instead.

Microsoft documents the detailed source-edition-to-target-edition paths in the SQL Server 2025 supported upgrades, SQL Server 2022 supported upgrades, and SQL Server 2019 supported upgrades tables. Confirm edition path, operating system support, installed features, and hardware requirements there before choosing the upgrade method.

Current SQL Server version and edition

Reads instance version, edition, build, update level, and the full version string.

SELECT
    SERVERPROPERTY('MachineName') AS machine_name,
    SERVERPROPERTY('ServerName') AS server_name,
    SERVERPROPERTY('InstanceName') AS instance_name,
    SERVERPROPERTY('Edition') AS edition,
    SERVERPROPERTY('ProductVersion') AS product_version,
    SERVERPROPERTY('ProductLevel') AS product_level,
    SERVERPROPERTY('ProductUpdateLevel') AS product_update_level,
    SERVERPROPERTY('ProductBuild') AS product_build,
    SERVERPROPERTY('EngineEdition') AS engine_edition,
    @@VERSION AS version_string;

ProductVersion and ProductBuild identify the exact source build. Edition affects upgrade rights, feature availability, and target-edition planning. ProductUpdateLevel helps compare the instance with the intended patch baseline. EngineEdition helps separate boxed SQL Server, Azure SQL, and other engine types. Older versions can return NULL for newer SERVERPROPERTY values; keep the full @@VERSION output with the assessment. Use this output with Microsoft supported upgrade path documentation before selecting the method.

Server configuration snapshot before upgrade

Reads all server-level configuration values so the test and cutover state can be compared.

SELECT
    name,
    value,
    value_in_use,
    description
FROM sys.configurations
ORDER BY name;

Use this as a record of current settings, not as a recommendation to change them. Compare value and value_in_use so pending configuration differences are visible. MAXDOP, cost threshold, backup compression, remote admin connections, and other settings can affect upgrade testing or post-cutover interpretation. Save the output before the test run and before production cutover so later behavior changes can be explained.

Choosing a SQL Server upgrade method

In-place upgrade changes the existing instance. Side-by-side upgrade builds a new target and moves databases, jobs, logins, and connection strings. The right method depends on rollback needs, outage tolerance, age of the source, operating system support, and how much cleanup is needed.

High availability designs need their own sequence. Availability Groups, failover clusters, log shipping, and replication can reduce downtime, but they also add order-of-operations and failback rules. If the source is too old for a direct path, or the server needs a platform change, treat the work as a migration rather than forcing the upgrade into the old host.

PathUse it when
In-place upgradeThe source is supported, the host is healthy, and a slower fallback path is acceptable.
Side-by-side upgradeRollback matters, the host is old, dependencies need cleanup, or the target should start clean.
MigrationThe work includes host, storage, cloud, architecture, or instance redesign.
Rolling upgradeAvailability Groups, failover clusters, log shipping, or replication can be sequenced deliberately.
RebuildThe current installation has configuration drift, old components, or host problems that should not be carried forward.

SQL Server upgrade planning for compatibility levels

Engine version and database compatibility level are separate decisions. Keeping the old compatibility level can reduce behavior changes during the engine upgrade, while a later compatibility-level change can unlock newer optimizer behavior after testing.

Query Store should be ready before compatibility changes when the source or test target supports it. It helps compare important queries before and after the change, and it gives you a way to investigate plan regressions without guessing from CPU alone.

Database compatibility levels

Lists user databases with compatibility level, recovery model, state, and read-only flag.

SELECT
    d.name AS database_name,
    d.compatibility_level,
    d.recovery_model_desc,
    d.state_desc,
    d.is_read_only,
    d.create_date
FROM sys.databases AS d
WHERE d.name NOT IN (N'master', N'model', N'msdb', N'tempdb')
ORDER BY d.compatibility_level, d.name;

compatibility_level shows which databases may retain older behavior after the engine upgrade. Read-only or offline databases need separate handling. This query avoids Query Store columns so it is more useful on older source instances. Do not change compatibility levels until the workload has been tested.

Database scoped configuration review

Run inside each important database to check optimizer-related database scoped settings.

SELECT
    DB_NAME() AS database_name,
    configuration_id,
    name,
    value,
    value_for_secondary
FROM sys.database_scoped_configurations
WHERE name IN (
    N'LEGACY_CARDINALITY_ESTIMATION',
    N'QUERY_OPTIMIZER_HOTFIXES',
    N'PARAMETER_SNIFFING',
    N'MAXDOP'
)
ORDER BY name;

LEGACY_CARDINALITY_ESTIMATION can explain why a database behaves differently from the engine default. QUERY_OPTIMIZER_HOTFIXES may affect plan behavior after version changes. PARAMETER_SNIFFING and MAXDOP settings should be understood before blaming the upgrade. On older source versions, run this later against the restored test target if the view is not available. Record settings before the upgrade so changes can be explained later.

Compatibility-level change template

Template only. Use it for a planned compatibility-level change after workload testing.

-- Template only. Change compatibility level after testing the workload.
-- Do not combine this with the engine upgrade unless it is part of the tested plan.

ALTER DATABASE [YourDatabase] SET COMPATIBILITY_LEVEL = 160;

Use the target level for the installed SQL Server version. Run this only after testing important queries and application workflows. Keep Query Store available so plan changes can be reviewed. Treat this as a separate change when the upgrade window is already tight.

SQL Server upgrade assessment for deprecated and removed features

Version upgrades can expose old syntax, discontinued components, unsupported features, driver limits, feature parity gaps, and application code that assumed older behavior. Review Microsoft upgrade notes, breaking-change notes, and vendor support matrices for the source and target versions.

Use the SSMS migration component and Upgrade Assessment for current assessment work. Older Data Migration Assistant outputs may still be useful context, but do not treat an old assessment as current without rerunning checks against the intended target version.

InputWhat to check
Microsoft upgrade notesSupported source versions, target edition, removed features, and special upgrade steps.
SSMS Upgrade AssessmentCompatibility issues, deprecated feature usage, and blockers found by assessment.
Vendor support matrixApplication, driver, SSIS, SSRS, reporting, and third-party tool support for the target version.
Application testsLogin, search, reports, batch jobs, integrations, and month-end workflows.

SQL Server upgrade dependency checks

SQL Server can upgrade successfully while scheduled work, linked servers, credentials, reports, drivers, or application connections fail. Dependency checks need to happen before and after the upgrade.

Include SQL Agent owners, proxies, operators, Database Mail, SSIS packages, reports, connection strings, linked server providers, and encryption or TLS requirements. SQL output alone cannot validate application behavior, so application smoke tests need named owners.

SQL Agent job history

Shows recent SQL Agent job steps, runtime, status, and messages.

WITH RecentJobHistory AS (
    SELECT
        h.job_id,
        h.step_id,
        h.step_name,
        h.run_status,
        h.run_date,
        h.run_time,
        h.run_duration,
        h.message
    FROM msdb.dbo.sysjobhistory AS h
    WHERE h.run_date >= CONVERT(int, CONVERT(char(8), DATEADD(day, -14, SYSDATETIME()), 112))
)
SELECT TOP (100)
    j.name AS job_name,
    j.enabled,
    h.step_id,
    h.step_name,
    h.run_status,
    DATETIMEFROMPARTS(
        h.run_date / 10000,
        (h.run_date % 10000) / 100,
        h.run_date % 100,
        h.run_time / 10000,
        (h.run_time % 10000) / 100,
        h.run_time % 100,
        0
    ) AS run_start_time,
    ((h.run_duration / 10000) * 3600)
      + (((h.run_duration % 10000) / 100) * 60)
      + (h.run_duration % 100) AS run_duration_seconds,
    h.message
FROM msdb.dbo.sysjobs AS j
LEFT JOIN RecentJobHistory AS h
    ON h.job_id = j.job_id
ORDER BY
    CASE WHEN h.run_date IS NULL THEN 1 ELSE 0 END,
    run_start_time DESC,
    j.name,
    h.step_id;

run_status identifies failed or retrying steps. run_duration_seconds helps find jobs that may not fit the upgrade window. message can show path, permission, package, or command problems. Enabled jobs without recent history still appear with empty history fields. Use this before upgrade test run and again after cutover.

Dependency inventory starting point

Counts common server-level dependencies that often affect upgrade and side-by-side moves.

SELECT
    N'Linked servers' AS dependency_type,
    (SELECT COUNT(*) FROM sys.servers AS s WHERE s.is_linked = 1) AS item_count,
    STUFF((
        SELECT TOP (10) N'; ' + QUOTENAME(s.name)
        FROM sys.servers AS s
        WHERE s.is_linked = 1
        ORDER BY s.name
        FOR XML PATH(''), TYPE
    ).value('.', 'nvarchar(max)'), 1, 2, N'') AS sample_items

UNION ALL

SELECT
    N'Credentials' AS dependency_type,
    (SELECT COUNT(*) FROM sys.credentials AS c) AS item_count,
    STUFF((
        SELECT TOP (10) N'; ' + QUOTENAME(c.name)
        FROM sys.credentials AS c
        ORDER BY c.name
        FOR XML PATH(''), TYPE
    ).value('.', 'nvarchar(max)'), 1, 2, N'') AS sample_items

UNION ALL

SELECT
    N'Enabled SQL Agent jobs' AS dependency_type,
    (SELECT COUNT(*) FROM msdb.dbo.sysjobs AS j WHERE j.enabled = 1) AS item_count,
    STUFF((
        SELECT TOP (10) N'; ' + QUOTENAME(j.name)
        FROM msdb.dbo.sysjobs AS j
        WHERE j.enabled = 1
        ORDER BY j.name
        FOR XML PATH(''), TYPE
    ).value('.', 'nvarchar(max)'), 1, 2, N'') AS sample_items

UNION ALL

SELECT
    N'Server triggers' AS dependency_type,
    (SELECT COUNT(*) FROM sys.server_triggers AS tr WHERE tr.is_disabled = 0) AS item_count,
    STUFF((
        SELECT TOP (10) N'; ' + QUOTENAME(tr.name)
        FROM sys.server_triggers AS tr
        WHERE tr.is_disabled = 0
        ORDER BY tr.name
        FOR XML PATH(''), TYPE
    ).value('.', 'nvarchar(max)'), 1, 2, N'') AS sample_items;

Linked servers may need provider, login, network, and encryption checks. Credentials can affect jobs, backups, proxies, and external access. Enabled SQL Agent jobs need ownership and post-upgrade validation. The query avoids STRING_AGG so it can run on older source instances. Server triggers, operators, Database Mail, and other server-level objects should be documented before the window.

SQL Server upgrade backup, restore, and rollback testing

Test the same SQL Server upgrade sequence you expect to run in production: final backups, restore test, final log backup where needed, CHECKDB, upgrade steps, application validation, job checks, monitoring checks, and rollback. A plan that only covers setup does not cover the service.

Rollback must include who decides, when the cutoff happens, how long fallback takes, and what data loss or replay steps are acceptable. If the old instance cannot be returned inside the outage window, that is not a rollback plan; it is a rebuild plan. Use the SQL Server backup guide and SQL Server recovery guide when backup or restore inputs are weak.

Backup readiness before upgrade

Shows latest full, differential, and log backups for each database before the upgrade window.

WITH LastBackups AS (
    SELECT
        bs.database_name,
        bs.type,
        MAX(bs.backup_finish_date) AS last_backup_finish_date
    FROM msdb.dbo.backupset AS bs
    WHERE bs.type IN ('D', 'I', 'L')
    GROUP BY bs.database_name, bs.type
)
SELECT
    d.name AS database_name,
    d.recovery_model_desc,
    d.state_desc,
    MAX(CASE WHEN lb.type = 'D' THEN lb.last_backup_finish_date END) AS last_full_backup,
    MAX(CASE WHEN lb.type = 'I' THEN lb.last_backup_finish_date END) AS last_differential_backup,
    MAX(CASE WHEN lb.type = 'L' THEN lb.last_backup_finish_date END) AS last_log_backup
FROM sys.databases AS d
LEFT JOIN LastBackups AS lb
    ON lb.database_name = d.name
WHERE d.name <> N'tempdb'
GROUP BY d.name, d.recovery_model_desc, d.state_desc
ORDER BY d.name;

last_full_backup is the minimum starting point for rollback and restore testing. last_log_backup matters for databases in full or bulk-logged recovery model. state_desc should be understood before the window starts. If backup coverage is weak, fix that before testing the upgrade.

CHECKDB validation template

Non-executing template for planned integrity checks before and after the upgrade test run.

-- Template only. Schedule this where the runtime and I/O load are acceptable.
-- Run before and after the upgrade test run, and record the output.

DBCC CHECKDB (N'YourDatabase') WITH NO_INFOMSGS;

CHECKDB can be resource-heavy; schedule it deliberately. Run it against restored copies when production impact is a concern. Record output before and after the test run. Do not use the upgrade window as the first time this command is tried.

SQL Server upgrade validation after cutover

SQL Server upgrade validation needs technical checks and application checks. SQL Server may be online while important queries regress, SQL Agent jobs fail, monitoring alerts break, backup jobs stop, or application workflows return different results.

Compare before and after plans, runtime, CPU, logical reads, waits, failed jobs, error logs, and application smoke-test output. Use the SQL Server monitoring guide, SQL Server waits guide, and SQL Server slow performance guide when validation shows a regression.

Query Store status

Run inside each important database to confirm Query Store state, storage, capture mode, and cleanup settings.

SELECT
    DB_NAME() AS database_name,
    actual_state_desc,
    desired_state_desc,
    readonly_reason,
    current_storage_size_mb,
    max_storage_size_mb,
    query_capture_mode_desc,
    size_based_cleanup_mode_desc,
    stale_query_threshold_days
FROM sys.database_query_store_options;

actual_state_desc should be READ_WRITE for useful capture. readonly_reason explains why Query Store may not be collecting data. current_storage_size_mb near max_storage_size_mb can stop useful capture. On old source versions without Query Store, run this against the restored test target after upgrade. Check this before and after upgrade or compatibility-level changes.

Query Store workload starting point

Lists high-duration Query Store entries as a starting point for before-and-after comparison.

SELECT TOP (50)
    qt.query_sql_text,
    q.query_id,
    p.plan_id,
    rs.count_executions,
    CAST(rs.avg_duration / 1000.0 AS decimal(18,2)) AS avg_duration_ms,
    CAST(rs.avg_cpu_time / 1000.0 AS decimal(18,2)) AS avg_cpu_ms,
    CAST(rs.avg_logical_io_reads AS decimal(18,2)) AS avg_logical_reads,
    rs.last_execution_time
FROM sys.query_store_runtime_stats AS rs
JOIN sys.query_store_plan AS p
    ON p.plan_id = rs.plan_id
JOIN sys.query_store_query AS q
    ON q.query_id = p.query_id
JOIN sys.query_store_query_text AS qt
    ON qt.query_text_id = q.query_text_id
ORDER BY rs.avg_duration DESC;

avg_duration_ms and avg_cpu_ms show candidates for comparison. avg_logical_reads helps find queries with plan or access-path sensitivity. last_execution_time confirms whether the query still matters recently. Use this with application context, not as a standalone blame list.

SQL Server upgrade rollback and go/no-go criteria

The go/no-go decision should be written before the outage window. Use the supported target, completed test run, restore checks, mapped dependencies, application tests, Query Store state, and measured rollback timing to decide.

A narrow change is often better than a heroic window. Patch the engine first, leave compatibility level for later, or switch to side-by-side if rollback timing is weak.

DecisionUse it when
GoThe path is tested, the target is supported, rollback is rehearsed, and application smoke tests pass.
DelayThe path is unsupported, backup coverage is weak, vendor support is unclear, or rollback timing is not measured.
NarrowPatch only, defer compatibility level, reduce cleanup, or use side-by-side instead of in-place.

What not to change during SQL Server upgrade planning

Upgrade windows punish extra changes. Keep the work focused, measured, and reversible wherever possible.

1

Do not treat setup success as upgrade validation.

2

Do not change compatibility level during the engine upgrade unless it was tested.

3

Do not combine the upgrade with unrelated cleanup, refactoring, or configuration tuning.

4

Do not skip backup, restore, and rollback testing.

5

Do not promise rollback unless it fits inside the real outage window.

6

Do not ignore SQL Agent jobs, linked servers, SSIS, reports, drivers, vendor support, and application connection strings.

7

Do not change MAXDOP, cost threshold, trace flags, or database-scoped settings in the same window unless they were tested.

8

Do not judge post-upgrade performance from CPU alone; check Query Store, waits, plans, errors, and business-critical workflows.

9

Do not use production as the first full test run.

When SQL Server upgrade planning needs support

SQL Server upgrade support makes sense when the source version is old, the path is not direct, compatibility-level behavior is unclear, rollback has not been tested, or important applications need a clean validation plan.

Send current version output, target version, edition, operating system, database list, compatibility levels, Query Store status, backup history, job history, dependency inventory, outage window, rollback expectation, vendor or application requirements, and the main reason for the upgrade.

Next step

If the upgrade path, compatibility-level plan, test run, or rollback timing is not ready, use the SQL Server upgrade support page or request help above.

Next useful reads: the SQL Server update guide for patch planning, the live updates tracker for current servicing context, SSMS downloads for Management Studio installers, the SQL Server migration guide for host moves, the SQL Server backup guide and SQL Server recovery guide for rollback inputs, and the SQL Server monitoring guide for post-upgrade checks.