Published: 2026-11-02

Restore a SQL Server .bak into Docker on an Apple Silicon Mac

To restore a .bak into SQL Server running in Docker on an M-series Mac: start the mcr.microsoft.com/mssql/server container (an x86-64 image that Docker Desktop, OrbStack or Colima run through Rosetta), copy the file in with docker cp, make sure the container’s mssql user (uid 10001) can read it, run RESTORE FILELISTONLY to get the logical file names, then RESTORE DATABASE … WITH MOVE to put the files under /var/opt/mssql/data/. The three errors people hit are Operating system error 5 (Access is denied) when the file’s permissions shut out the mssql user, Use WITH MOVE to identify a valid location when the backup came from Windows, and error 3169 when the backup is from a newer SQL Server than the container. Below is every step with the output we got. We ran the commands on a Linux x86-64 machine, not a Mac, on November 1, 2026; the Docker and SQL commands are the same on a Mac, and the Mac-specific parts are marked and sourced.

SQL Server on Apple silicon in November 2026 (Mac-specific)

  • The images are x86-64 only. docker manifest inspect mcr.microsoft.com/mssql/server:2025-latest returns a single image manifest, not a multi-platform list, and the image reports amd64. Microsoft’s Docker quickstart says the images are “supported only on Linux hosts running on Intel and AMD x86-64 CPUs” and that “Emulation or translation environments (for example, Rosetta 2, Prism, or QEMU) aren’t tested or supported.” A Microsoft engineer wrote in mssql-docker #802 (October 2025) that “ARM is not supported at this time.”
  • Docker Desktop runs amd64 images with Rosetta when Use Rosetta for x86_64/amd64 emulation on Apple Silicon is ticked in its settings (it needs the Apple Virtualization framework). Docker’s 4.25 release notes say Rosetta is on by default on macOS 14.1 and later, while the settings reference lists the option as off by default, so check the box.
  • OrbStack “uses Rosetta to run images built for Intel CPUs (x86_64/amd64 architecture)” (OrbStack docs). Colima needs a VM started with colima start --vm-type=vz --vz-rosetta (Colima README; macOS 13 or later).
  • --platform linux/amd64 is optional. The image exists only for amd64, so Docker pulls that one either way; the flag just makes the choice explicit.
  • SQL Server 2025 under Rosetta had a rough start. In #802 Microsoft said that “With SQL Server 2025… we identified issues impacting this scenario.” #942 (2025 images crashing on macOS 26 Tahoe) was closed in February 2026 after users reported that the CU1 image starts; that report comes from users, not Microsoft. If a 2025 container exits seconds after starting, pull the image again.
  • Azure SQL Edge is gone. It used to be the ARM64 workaround; Microsoft’s overview page says it “is retired as of September 30, 2025” and “no longer supports the ARM64 platform.”
  • Rosetta itself has an end date for apps. Apple says Rosetta stays available through macOS 27 as a general-purpose tool. For Linux virtual machines, which is how Docker runs containers on a Mac, Apple’s Virtualization documentation says macOS 27 integrates Intel binary translation without installing Rosetta. Apple has not said what happens after that.

For the bigger picture (SQL Server on a remote x86-64 machine, SSMS in a Windows VM), see How to Run SQL Server on a Mac. The rest of this post assumes the container runs.

1. Start the container

docker run -d --name sql2025 --platform linux/amd64 \
  -e ACCEPT_EULA=Y -e 'MSSQL_SA_PASSWORD=<YourStrong@Passw0rd>' \
  -p 1433:1433 mcr.microsoft.com/mssql/server:2025-latest

Put the password in single quotes so the shell leaves characters like ! and $ alone. The container runs as a non-root user: docker exec sql2025 id printed uid=10001(mssql) gid=10001(mssql), which matches Microsoft’s container security page (“Containers for SQL Server 2019 (15.x) and later versions automatically start up as non-root”). The image declares no volume, so the databases you restore live in the container’s own filesystem and are deleted with docker rm.

Current images ship sqlcmd at /opt/mssql-tools18/bin/sqlcmd. The container’s certificate is self-signed, so we added -C to every call, which per the sqlcmd reference trusts the server certificate without validating it. Our server reported Microsoft SQL Server 2025 (RTM-CU8) - 17.0.4075.5 (X64).

2. Get the .bak into the container

Create a folder for backups and copy the file in. We used Microsoft’s AdventureWorks2022.bak sample (200 MB, taken on SQL Server 2022 on Windows):

docker exec sql2025 mkdir -p /var/opt/mssql/backup
docker cp AdventureWorks2022.bak sql2025:/var/opt/mssql/backup/

docker exec runs as mssql, so the folder belongs to mssql. The copied file does not: in our run it kept the numeric owner from the host and its mode. Check before you restore:

$ docker exec sql2025 ls -ln /var/opt/mssql/backup/
-rw------- 1 1000 1000 209838080 Nov  1 11:31 AdventureWorks2022.bak

A file readable by everyone (mode 0644, common for browser downloads) restores fine whoever owns it. A 0600 file, which tools like scp or a backup script can leave you with, does not.

3. Operating system error 5: the mssql user can’t read the file

This is what the 0600 file above gave us:

$ docker exec sql2025 /opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P '<password>' -C \
    -Q "RESTORE FILELISTONLY FROM DISK = N'/var/opt/mssql/backup/AdventureWorks2022.bak'"
Msg 3201, Level 16, State 2, Server 253ecac92bdb, Line 1
Cannot open backup device '/var/opt/mssql/backup/AdventureWorks2022.bak'. Operating system error 5(Access is denied.).
Msg 3013, Level 16, State 1, Server 253ecac92bdb, Line 1
RESTORE FILELIST is terminating abnormally.

Give the file to mssql. -u 0 runs the command as root inside the container:

docker exec -u 0 sql2025 chown mssql:mssql /var/opt/mssql/backup/AdventureWorks2022.bak

A wrong path gives the same Msg 3201 with a different operating system error: Operating system error 2(The system cannot find the file specified.). The path is the one inside the container, not the one on your Mac.

4. RESTORE FILELISTONLY, then RESTORE WITH MOVE

A backup remembers where its data and log files lived. RESTORE FILELISTONLY lists them (columns trimmed):

LogicalName             PhysicalName                                                                                Type
AdventureWorks2022      C:\Program Files\Microsoft SQL Server\MSSQL16.MSSQLSERVER\MSSQL\DATA\AdventureWorks2022.mdf      D
AdventureWorks2022_log  C:\Program Files\Microsoft SQL Server\MSSQL16.MSSQLSERVER\MSSQL\DATA\AdventureWorks2022_log.ldf  L

Those Windows paths don’t exist in a Linux container, so a plain RESTORE DATABASE AdventureWorks2022 FROM DISK = N'…' fails while planning:

Msg 5133, Level 16, State 1, Line 1
Directory lookup for the file "C:\Program Files\Microsoft SQL Server\MSSQL16.MSSQLSERVER\MSSQL\DATA\AdventureWorks2022.mdf" failed with the operating system error 2(The system cannot find the file specified.).
Msg 3156, Level 16, State 3, Line 1
File 'AdventureWorks2022' cannot be restored to 'C:\Program Files\Microsoft SQL Server\MSSQL16.MSSQLSERVER\MSSQL\DATA\AdventureWorks2022.mdf'. Use WITH MOVE to identify a valid location for the file.
(the same two messages for AdventureWorks2022_log)
Msg 3119, Level 16, State 1, Line 1
Problems were identified while planning for the RESTORE statement. Previous messages provide details.
Msg 3013, Level 16, State 1, Line 1
RESTORE DATABASE is terminating abnormally.

Move each logical file to the container’s data folder. SERVERPROPERTY('InstanceDefaultDataPath') returned /var/opt/mssql/data/ for both data and log files:

RESTORE DATABASE AdventureWorks2022
FROM DISK = N'/var/opt/mssql/backup/AdventureWorks2022.bak'
WITH MOVE N'AdventureWorks2022'     TO N'/var/opt/mssql/data/AdventureWorks2022.mdf',
     MOVE N'AdventureWorks2022_log' TO N'/var/opt/mssql/data/AdventureWorks2022_log.ldf',
     STATS = 25;
25 percent processed.
50 percent processed.
75 percent processed.
100 percent processed.
Processed 25376 pages for database 'AdventureWorks2022', file 'AdventureWorks2022' on file 1.
Processed 2 pages for database 'AdventureWorks2022', file 'AdventureWorks2022_log' on file 1.
Converting database 'AdventureWorks2022' from version 957 to the current version 998.
Database 'AdventureWorks2022' running the upgrade step from version 957 to version 958.
(40 more upgrade steps)
RESTORE DATABASE successfully processed 25378 pages in 0.192 seconds (1032.613 MB/sec).

On our machine the whole statement took 1.7 seconds, including the upgrade steps. The database came up ONLINE with compatibility level 160, the level it had on SQL Server 2022: restoring onto a newer server upgrades the file format but keeps the compatibility level. SELECT COUNT(*) FROM Person.Person returned 19,972. Expect it to be slower under Rosetta on a Mac; we did not time it there.

The same FILELISTONLY-then-MOVE flow is in Microsoft’s container tutorial. Its commands leave out -C, which current sqlcmd needs for the container’s self-signed certificate.

5. Error 3169: the backup is from a newer SQL Server

We backed up a small database on the 2025 container and restored it on a SQL Server 2022 container (CU26, 16.0.4265.3):

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.

Microsoft’s RESTORE reference is plain about it: “No SQL Server backup can be restored to an earlier version of SQL Server than the version on which the backup was created.” There is no option that gets around it. Note that RESTORE HEADERONLY and RESTORE FILELISTONLY still worked on the older server, so you can check a file before you pick an image: HEADERONLY returned SoftwareVersionMajor 17 and DatabaseVersion 998 for our 2025 backup, and 16 and 957 for the AdventureWorks2022 sample. Then:

  • run an image at least as new as the source: the 2025-latest tag restored the 2022 sample above;
  • or ask for a BACPAC (next section) or a script of the schema and data, which older versions can import as long as the objects in it exist there.

Bind mounts instead of docker cp

With -v ~/sqlbackups:/var/opt/mssql/backup the container sees a host folder directly. That saves copying large files, but the mssql user still needs access. On our Linux host, with the folder owned by our user and mode 0755:

  • reading a 0644 file worked (RESTORE FILELISTONLY returned its file list); a 0600 file failed with the same Msg 3201 and operating system error 5;
  • BACKUP DATABASE … TO DISK = N'/var/opt/mssql/backup/msdb.bak' failed with Cannot open backup device … Operating system error 5(Access is denied.) and BACKUP DATABASE is terminating abnormally., because uid 10001 can’t write to the folder;
  • after chmod 777 on the folder the backup worked, and the new file on the host belonged to uid 10001 with mode 0640, so our own user could not read it without sudo. Microsoft’s security page suggests chown -R 10001:0 on the host folder instead.

We did not test bind mounts on a Mac. Docker Desktop and OrbStack share Mac folders with the Linux VM through their own file-sharing layer, so the owners and modes the container sees can differ from the ones on a Linux host. If a restore from a bind mount fails there with operating system error 5, copy the file in with docker cp and chown it as in step 3.

BACPAC files: SqlPackage now that Azure Data Studio is retired

A .bacpac holds schema and data instead of database pages, so it moves between versions and to Azure SQL Database. Microsoft’s retirement notice says “Azure Data Studio is retired as of February 28, 2026”, and its BACPAC wizard went with it. Three ways that remain on a Mac:

  • SqlPackage, Microsoft’s command-line tool. The download page lists version 170.5.96 (September 15, 2026), macOS 14 and later, and installation as a .NET tool with dotnet tool install -g microsoft.sqlpackage. The macOS zip download is an x64 build; the .NET tool package is not tied to a processor, so on an Apple-silicon Mac it should run on an arm64 .NET SDK, though Microsoft does not say so explicitly and we did not try it on a Mac.
  • The VS Code MSSQL extension, Microsoft’s recommended replacement for Azure Data Studio, has Import BACPAC into a new or empty database.
  • Jam SQL Studio’s Import Data-tier Application (below).

We ran SqlPackage 170.4.83.3 (the self-contained Linux download) against a 2025 container: an export of a two-row database, then an import into a new database:

sqlpackage /Action:Export /TargetFile:BlogShop.bacpac \
  /SourceConnectionString:"Server=localhost,1433;Database=BlogShop;User ID=sa;Password=<password>;TrustServerCertificate=True"

sqlpackage /Action:Import /SourceFile:BlogShop.bacpac \
  /TargetConnectionString:"Server=localhost,1433;Database=BlogShopCopy;User ID=sa;Password=<password>;TrustServerCertificate=True"
Importing to database 'BlogShopCopy' on server 'localhost,14399'.
Creating deployment plan
…
Processing Table '[dbo].[Orders]'.
Enabling indexes.
Successfully imported database.
Time elapsed 0:00:14.27

Two errors to expect:

*** Error importing database:Data cannot be imported into target because it contains one or more user objects. Import should be performed against a new, empty database.
Error SQL71659: Data cannot be imported into target because it contains one or more user objects. Import should be performed against a new, empty database.

That one came from importing into a database that already had tables: pick a new name. Without TrustServerCertificate=True, the connection to the container failed before the import started:

*** Encryption is enabled by default on connections.  More information is available at https://aka.ms/dacfx-connection
*** Error importing database:Could not import package.
Unable to connect to target server 'localhost,14399'. …
Certificate failed chain validation. Error(s): 'self-signed certificate, [Status: UntrustedRoot]

Our test server listened on port 14399, which is why that number shows in the output. Instead of the connection-string option you can pass /TargetTrustServerCertificate:True, per the Import action reference.

The same restore in Jam SQL Studio

Jam SQL Studio is a native Apple-silicon app, so only the server runs under Rosetta. Connect to localhost, port 1433, SQL login sa, with Trust server certificate ticked for the container’s self-signed certificate. Then:

  1. Copy the file into the container and fix its owner as in steps 2 and 3. The restore reads the file on the server, which is the container, not your Mac.
  2. Right-click Databases in Object Explorer and choose Restore Database (.bak)….
  3. Type the path in Backup file path on SQL Server (/var/opt/mssql/backup/AdventureWorks2022.bak), or click Browse… to pick it from the server’s folders. Use server default fills in the instance’s default backup folder, which in our container was /var/opt/mssql/data.
  4. Set the Target database name, the Recovery state (RECOVERY to use the database right away) and, to replace a database with the same name, Overwrite existing database (WITH REPLACE).
  5. Click Start Restore.

Before it restores, the dialog runs RESTORE FILELISTONLY itself and adds a MOVE for every file, into the instance’s default data and log folders (InstanceDefaultDataPath, /var/opt/mssql/data/ here), named after the target database: <name>.mdf, <name>_log.ldf, and <name>_1.ndf and so on for extra data files. That takes care of the Windows-path error in step 4. Progress comes from STATS, and the operation can be cancelled. If the server can’t read the file, the dialog says Access denied to backup file and that the SQL Server service account does not have permission to read it, which in a container means the chown from step 3. Error 3169 shows SQL Server’s own message: no client can restore a backup onto an older server.

For a BACPAC, right-click the connection and choose Import Data-tier Application (.bacpac)…. The import runs through the SQL Tools Service that ships with the app and reads the file from a folder on your Mac, so nothing has to be copied into the container. Restoring a backup has no size limit in the free Personal mode; the Backup and Restore guide covers backups, PostgreSQL dumps and the 1 GB limit on creating backups in Personal mode.

Some context from our anonymous telemetry: of the devices that connected to SQL Server from Jam SQL Studio in the 30 days to October 27, 2026, 252 ran macOS, 84 Windows and 42 Linux. A backup or restore was started from the app in 31 sessions in 60 days. These are small counts from one app, and they do not say where those servers run.

Quick Answers

Q: Can I run SQL Server in Docker on an Apple Silicon Mac?

A: Yes, through x86-64 translation. Microsoft publishes the mcr.microsoft.com/mssql/server images for amd64 only, so Docker Desktop, OrbStack and Colima run them with Rosetta. Microsoft's Docker quickstart says emulation or translation environments such as Rosetta 2 aren't tested or supported, so treat it as a development setup. Azure SQL Edge, the old ARM64 option, was retired on September 30, 2025.

Q: How do I fix Operating system error 5 (Access is denied) when restoring a .bak in Docker?

A: SQL Server in the container runs as the mssql user (uid 10001), and it cannot read a backup file that another user owns with mode 0600. Change the owner inside the container with docker exec -u 0 <container> chown mssql /var/opt/mssql/backup/<file>.bak, or make the file readable before you copy it. A folder bind-mounted from a Linux host also needs to be writable by uid 10001 before BACKUP can write to it.

Q: What does 'Use WITH MOVE to identify a valid location for the file' mean?

A: The backup records where the data and log files lived on the original server, for example C:\Program Files\Microsoft SQL Server\...\DATA on Windows, and that folder does not exist in the Linux container. Run RESTORE FILELISTONLY to get the logical file names, then RESTORE DATABASE ... WITH MOVE for each one to /var/opt/mssql/data/.

Q: How do I fix error 3169 when restoring a backup?

A: The backup comes from a newer SQL Server than the one in your container, and no SQL Server backup can be restored to an earlier version. RESTORE HEADERONLY shows the source version in SoftwareVersionMajor (16 for SQL Server 2022, 17 for 2025). Run a container image of that version or newer, such as mcr.microsoft.com/mssql/server:2025-latest, or ask for a BACPAC or a script instead.

Q: How do I import a BACPAC on a Mac now that Azure Data Studio is retired?

A: Azure Data Studio was retired on February 28, 2026. Use SqlPackage, which installs as a .NET tool with dotnet tool install -g microsoft.sqlpackage, and run sqlpackage /Action:Import with a TargetConnectionString that includes TrustServerCertificate=True for a container. The VS Code MSSQL extension and Jam SQL Studio can also import a BACPAC. Import needs a new or empty database.

Q: Should I use docker cp or a bind mount for the .bak file?

A: docker cp copies the file into the container's own filesystem, where you can fix its owner with chown, and the copy disappears with the container. A bind mount shows a host folder inside the container, which is handy for many backups, but the container user still needs read access to restore and write access to back up. In our Linux test both failed with operating system error 5 until the permissions allowed uid 10001.

How we tested

All commands ran on November 1, 2026 on an x86-64 Linux machine with Docker, in throwaway containers that we removed afterwards: mcr.microsoft.com/mssql/server:2025-latest (SQL Server 2025 CU8, 17.0.4075.5) and 2022-latest (SQL Server 2022 CU26, 16.0.4265.3). Server names in the output are container IDs. The backup was Microsoft’s AdventureWorks2022.bak; the 3169 test used a two-row database we created. SqlPackage was the 170.4.83.3 Linux download. The Apple-silicon section is sourced from Microsoft, Docker, OrbStack, Colima and Apple documentation and the mssql-docker issue tracker, linked where it appears; we did not run these steps on a Mac. The device and session counts are from Jam SQL Studio’s anonymous telemetry.

Summary

On an Apple-silicon Mac the SQL Server container runs as an x86-64 image under Rosetta, which Microsoft does not support but which is how most Mac developers run it. Copy the .bak in with docker cp, chown it to mssql if it is not world-readable, read the logical names with RESTORE FILELISTONLY, and RESTORE … WITH MOVE them to /var/opt/mssql/data/. Error 5 means permissions, error 5133 with 3156 means a missing MOVE, and error 3169 means you need a newer image. For BACPAC files, use SqlPackage, the VS Code MSSQL extension or Jam SQL Studio now that Azure Data Studio is retired.

Last verified against learn.microsoft.com, docs.docker.com, docs.orbstack.dev, the Colima README, developer.apple.com and github.com/microsoft/mssql-docker, and by running every command in SQL Server 2025 and 2022 containers, on 2026-11-01.

Related