Restore From a Newer SQL Server Version (Error 3169)

🚨Part of the SQL Server Errors series, the exact messages and what actually causes them.In: Backup & Recovery

Msg 3169  ·  Severity 16  ·  State 1
The database was backed up on a server running database version 998. That version is incompatible with this server, which supports version 958. Either restore the database on a server that supports the backup, or use a backup that is compatible with this server.
⚡The backup is from a newer version of SQL Server than the server you are restoring to, and there is no option, flag or hotfix that changes that. The two numbers in the message are the answer: the first is the backup, the second is the highest this instance can open. Your real choices are to upgrade or rebuild the target, or move the schema and the data rather than the database.

This usually turns up at the worst possible moment, when a production backup has been copied onto an older development or DR box and the restore is the last step of something that was supposed to take twenty minutes. The backup file is fine. The server will not open it.

SQL Server upgrades a database the first time a newer engine opens it, and that upgrade is one-way. Nothing writes the old format back. So a database that has ever been on a newer version cannot be restored, attached or made to work on an older one, and the sooner you accept that the sooner you pick one of the routes further down.


Read the Two Numbers in the Message

Everything you need to decide what to do next is already in the error. The first number is the internal database version stamped into the backup, the second is the highest internal version this instance can open. You do not have to look either of them up to know you are stuck, you only need them to work out how far apart the two servers are.

You can read both for yourself. The backup header still opens even though the restore will not, which is the part that misleads people:

-- Works against a backup your instance cannot restore.
RESTORE HEADERONLY FROM DISK = N'D:\Backup\Sales.bak';

-- What this instance stamps on its own databases.
SELECT DATABASEPROPERTYEX('master', 'Version') AS db_version,
       CONVERT(varchar(30), SERVERPROPERTY('ProductVersion')) AS build;

The header is about sixty columns wide and six of them answer the question. On a SQL Server 2022 instance reading a backup made on SQL Server 2025, that run returned DatabaseVersion 998, CompatibilityLevel 170, SoftwareVersionMajor 17, SoftwareVersionMinor 0, SoftwareVersionBuild 4075 and BackupTypeDescription Database.

SoftwareVersionMajor is the one to read first, because it maps straight onto the product name. A 17 is SQL Server 2025, a 16 is SQL Server 2022, and the gap between that and the major version of your target tells you how big the job is. DatabaseVersion is the internal stamp the engine actually checks, and it is the number the error quotes. On the two instances behind this post, the 2025 instance stamps 998 and the 2022 instance stamps 957 while reporting that it supports up to 958. SQL Server Builds: Complete Version List and Support Lifecycle is the lookup for turning a build number into a product and a support date.


What Still Works and What Does Not

This catches people out, so it is worth stating plainly. Against the same backup file, on the same older instance, two of the three read-only RESTORE commands succeed:

  • RESTORE HEADERONLY succeeds. It reads the backup header, which has not changed format.
  • RESTORE FILELISTONLY succeeds. Logical file names and sizes, which is why people assume the restore is one WITH MOVE away.
  • RESTORE VERIFYONLY fails with 3169, because verifying means checking it could be restored here, and it could not.
  • RESTORE DATABASE fails with 3169, followed by 3013.

The actual restore attempt, captured on the 2022 instance:

Msg 3169, Level 16, State 1, Line 1
The database was backed up on a server running database version 998. That version is incompatible with this server, which supports version 958. Either restore the database on a server that supports the backup, or use a backup that is compatible with this server.
Msg 3013, Level 16, State 1, Line 1
RESTORE DATABASE is terminating abnormally.

That 3013 is the generic “the restore stopped” message and it carries no information of its own. If you arrived here from 3013 and the line above it is not 3169, RESTORE Is Terminating Abnormally (Errors 3013 and 3241) covers the other causes. If the complaint is about a different database rather than a version, that is The Backup Set Holds a Backup of a Database Other Than the Existing Database (Error 3154).


Attaching the Data Files Fails the Same Way (Error 948)

The next idea is always the same: skip the backup, copy the .mdf and .ldf across and attach them. It fails for the same reason with a different number, and the wording is blunter:

Msg 948  ·  Severity 20  ·  State 1
The database ‘Lab1001_att’ cannot be opened because it is version 998. This server supports version 958 and earlier. A downgrade path is not supported.

With the data files copied from a SQL Server 2025 instance to a SQL Server 2022 one, CREATE DATABASE ... FOR ATTACH returns Msg 1813, Level 16, State 2, “Could not open new database ‘Lab1001_att’. CREATE DATABASE is aborted.”, and then the 948 above.

Severity 20 and the phrase “a downgrade path is not supported” are the engine being as clear as it ever gets. Note also that the file numbers are the same 998 and 958 as the backup, because the stamp lives in the data file and the backup simply carries a copy of it. Detach and attach is documented in Database detach and attach, and MS Docs has the error itself as MSSQLSERVER_948.


Setting the Compatibility Level Does Not Help

This is the single most common wasted hour on this problem, so it gets its own section. Compatibility level and internal database version are different things that both look like version numbers.

  • Compatibility level (110, 120, 130 up to 170) controls query optimiser and language behaviour. It is a setting you change at any time with ALTER DATABASE, and in the backup header it shows as CompatibilityLevel 170.
  • Internal database version (the 998 and 958 in the error) is the physical on-disk format. It is not a setting. The engine raises it when it opens a database for the first time and there is no command that lowers it.

Setting a database on the newer server to compatibility level 160 before you back it up changes the second number and not the first, so the backup still carries 998 and the restore still fails with 3169. There is no point taking a fresh backup after changing it.


The Routes That Actually Work

There are only two shapes of answer here. Either the target stops being older, or you stop moving a database and start moving its contents.

1. Upgrade or rebuild the target. This is the right answer far more often than people expect, because the target is usually a development or DR box that is behind by accident rather than by policy. An in-place upgrade or a side-by-side build both work, and SQL Server Version Upgrade Runbook is the sequence. Run Get Migration Risk Assessment against the source first so that the upgrade is a decision rather than a surprise. MS Docs lists what each version can be upgraded from in Supported version and edition upgrades.

2. Script the schema and move the data. When the target genuinely has to stay where it is, you rebuild the database rather than restore it. Three tools, in order of how much you are moving:

  • Generate Scripts in SSMS, with Advanced set to script schema and data, and the target server version set to the older one so that it refuses to emit syntax the target cannot parse. Fine up to a few hundred megabytes, painful beyond that. MS Docs: Generate and publish scripts.
  • A dacpac or bacpac. A dacpac carries schema, a bacpac carries schema and data, and both are version-aware, so a dacpac built against the older target will tell you up front which objects it cannot create. This is the route to prefer when the schema is large and the data is not. MS Docs: Data-tier applications.
  • Schema by script, data by bcp. For anything large this is the one that finishes. Create the schema on the target without indexes or foreign keys, bulk copy the tables out and in, then add the constraints and indexes. MS Docs: bcp utility.

Whichever you pick, the thing people forget is everything that is not in the database. Logins, SQL Server Agent jobs, linked servers, certificates and server-level settings do not travel in a script of one database, and on a restore they would not have travelled either. SQL Server Migration Runbook: Standalone Instance has the list.

What is not a route: there is no WITH option on RESTORE that downgrades, no trace flag, no supported tool from Microsoft that converts a data file to an older format, and no cumulative update that adds one. The restriction is stated in Restore and recovery overview and the command reference is RESTORE statements.


How Not to Be Here Again

Two habits remove this from your year entirely.

Upgrade the lower environments first. Development and DR boxes being behind production is the direct cause of every instance of this error. Upgrading production first and leaving them is the ordering that breaks the restore test, and the restore test is the thing you most need to keep working.

Record the version alongside every backup. If your restore script reads the header before it restores, it can say “this backup is from a newer version” in plain words instead of surfacing 3169 at 2am. Generate Restore With Move Script and How to Restore a Database in SQL Server are where that check belongs.


Common Questions

Can I restore a SQL Server 2022 backup to SQL Server 2019?
No, and the same answer applies to every pair where the backup is the newer one. Restoring forward is supported and normal, restoring backward is not supported at all. The error you get is 3169 and it names both internal version numbers.
What if I set the compatibility level down before taking the backup?
It makes no difference. Compatibility level is a query behaviour setting, the internal database version is the physical file format, and only the second one is checked at restore time. A database at compatibility level 160 on a 2025 instance still has internal version 998 and still fails with 3169.
RESTORE HEADERONLY worked, so why will the restore not?
The backup header is readable by older versions on purpose, which is how a restore tool can tell you what is in a file before trying it. The pages inside are in the newer format. HEADERONLY and FILELISTONLY both returned full results on the older instance while VERIFYONLY and RESTORE DATABASE both failed with 3169.
Can I copy the mdf and ldf and attach them instead?
No. That fails with error 948, severity 20, and the message says “a downgrade path is not supported” in those words. The version stamp lives in the data file itself, so the backup and the data file carry the same number.
Is there a tool that downgrades a database?
Not from Microsoft, and the third-party ones you will find are doing a schema and data export under a different name. If that is the route you are taking, use Generate Scripts, a dacpac, or bcp, where the behaviour is documented and the failures are visible.
How big a job is the script and copy route really?
It scales with the data, not the schema. Generate Scripts with data included is fine for a small database and becomes unusable somewhere in the low gigabytes. Past that, script the schema without indexes, bcp the tables, then create the indexes and constraints, and expect the index build to be the longest step. Plan it as a migration with a tested rollback, not as a long restore.

Where To Go Next

The restore failures that look like this one but are not, and the migration that replaces it.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *