SQL Server Linux Container Images Got Smaller: Image Size and Startup Time Across Cumulative Updates

Page content

This week I was at PASS Data Community Summit in Seattle, and I attended a session called “An Inside Look at How Microsoft Builds SQL Features, by Bob Ward, Naveen Prakash, and Travis Wright, all of whom are on the SQL Server team. In this session, Travis mentioned that they reduced the SQL Server container image size by a meaningful amount using AI agents that helped discover unused code in the image, but details on how much and when were lost when the conversation moved on to the next topic. So I set out to find out exactly which SQL Server build this came out in, and I also wanted to measure how much we saved. They also mentioned that startup times were better now.

I use SQL Server containers nearly every day, and I’ve written a ton about containers on this blog, so I got to work. So I pulled the CU images for SQL Server 2025 and SQL Server 2022, measured each one, and timed how long it took to get from docker run to a successful query.

In this post, I’m going to show you where the images got a lot smaller, including a 25% smaller download for SQL Server 2025 CU11, and I’ll show you that the smaller images didn’t start any faster in my testing. Let’s go.

The Test Setup

Here’s what I tested on my Mac, running through Rosetta: I used images from mcr.microsoft.com/mssql/server and started one fresh container per tag, from the newest CU to the oldest.

To isolate the impact of the cumulative update, I stuck with one base OS for each major version:

  1. SQL Server 2025: CU1 through CU11, using the Ubuntu 22.04 tags.
  2. SQL Server 2022: CU1 and CU3 through CU28, using the Ubuntu 20.04 tags. CU2 isn’t in the registry’s tag list.

For each image, I captured three measurements:

  • Compressed layers: the sum of the layer sizes in the registry manifest. This approximates the bytes you download when you pull the image.
  • Local image size: what docker image inspect reports for the pulled image.
  • Startup to query: wall-clock seconds from just before docker run -d until sqlcmd connected and returned SELECT SERVERPROPERTY('ProductVersion').

The startup number is a coarse, end-to-end measurement. It includes Docker creating and starting the container, so it’s more than SQL Server’s own startup time. I polled for a connection every half second.

SQL Server 2025 Results

Let’s start with SQL Server 2025. In the table below, sizes are in decimal units and the startup time is from a single run per tag.

Tag Product Version Compressed Layers (MB) Local Image (GB) Startup to Query (s)
2025-CU11 17.0.5065.9 480.7 2.221 8.64
2025-CU10 17.0.5035.5 640.1 2.434 8.03
2025-CU9 17.0.5005.3 638.1 2.427 8.80
2025-CU8 17.0.4075.5 636.9 2.423 8.78
2025-CU7 17.0.4065.4 636.3 2.420 9.49
2025-CU6 17.0.4055.5 664.6 2.525 8.52
2025-CU5 17.0.4045.5 661.7 2.515 8.97
2025-CU4 17.0.4035.5 661.8 2.515 8.35
2025-CU3 17.0.4025.3 657.9 2.500 8.45
2025-CU2 17.0.4015.4 655.6 2.493 8.58
2025-CU1 17.0.4006.2 653.2 2.485 7.52

As you can see in the table above, every image from CU1 through CU10 lands between about 636 and 665 MB compressed. Then CU11 drops to 480.7 MB. That’s 159 MB, or 24.9%, less to download than CU10. The local image is 213 MB, or 8.7%, smaller too.

Notice the startup column, though. CU11 took 8.64 seconds, and CU10 took 8.03 seconds. A smaller image didn’t get me a faster start. More on that in a bit.

SQL Server 2022 Results

SQL Server 2022 is where things get interesting. Here’s every CU I tested, and three of them really stand out.

Tag Product Version Compressed Layers (MB) Local Image (GB) Startup to Query (s)
2022-CU28 16.0.4325.4 474.7 2.167* 6.85
2022-CU27 16.0.4295.3 618.4 2.309 6.10
2022-CU26 16.0.4265.3 618.0 2.308 6.12
2022-CU25 16.0.4255.1 615.0 2.299 6.15
2022-CU24 16.0.4245.2 606.5 2.275 6.52
2022-CU23 16.0.4236.2 606.1 2.274 6.11
2022-CU22 16.0.4225.2 606.1 2.274 6.59
2022-CU21 16.0.4215.2 606.1 2.274 7.13
2022-CU20 16.0.4205.1 612.8 2.297 6.31
2022-CU19 16.0.4195.2 603.5 2.265 6.20
2022-CU18 16.0.4185.3 611.6 2.292 6.34
2022-CU17 16.0.4175.1 601.4 2.256 6.19
2022-CU16 16.0.4165.4 582.9 2.205 6.44
2022-CU15 16.0.4145.4 583.2 2.206 6.22
2022-CU14 16.0.4135.4 582.6 2.204 6.33
2022-CU13 16.0.4125.3 579.7 2.194 6.66
2022-CU12 16.0.4115.5 580.7 2.197 6.65
2022-CU11 16.0.4105.2 573.9 2.180 6.89
2022-CU10 16.0.4095.4 572.2 2.173 6.14
2022-CU9 16.0.4085.2 572.4 2.173 6.43
2022-CU8 16.0.4075.1 1,036.7 3.962 6.13
2022-CU7 16.0.4065.3 1,037.1 3.963 6.26
2022-CU6 16.0.4055.4 1,037.2 3.962 6.37
2022-CU5 16.0.4045.3 572.0 2.175 6.32
2022-CU4 16.0.4035.4 571.4 2.172 6.47
2022-CU3 16.0.4025.1 574.2 2.200 6.74
2022-CU1 16.0.4003.1 574.9 2.204 6.77

Here’s what jumps out:

  • CU6, CU7, and CU8 are about double the size: roughly 1 GB compressed and almost 4 GB locally. CU5, right before them, is 572 MB compressed and 2.175 GB locally.
  • CU9 brings it right back down: going from CU8 to CU9 cuts 464 MB (44.8%) from the download and 1.79 GB (45.2%) from the local image.
  • CU28 drops again: compressed layers go from 618.4 MB in CU27 to 474.7 MB in CU28. That’s 144 MB, or 23.2%, less to download.
  • The images grow in between: from CU9 through CU27, the download goes from 572 MB to 618 MB.

What’s Actually Happening

So why are CU6 through CU8 so big? I looked at the layer history for a few of these images with docker history --no-trunc. Here’s what I found around the SQL Server payload layers, with approximate sizes:

  • 2022 CU5: a 1.33 GB COPY payload layer and a 195 MB install layer.
  • 2022 CU6 and CU8: a 1.33 GB COPY install.tar layer, a second 1.33 GB extraction layer, and a 193 MB install layer.
  • 2022 CU9: a 1.33 GB extraction layer and a 193 MB install layer. The separate COPY install.tar layer is gone.

That’s consistent with CU6 through CU8, which carry the install archive in one layer and the extracted files in another. If that’s what’s going on, those images store the same payload twice. In CU9, the archive layer is gone. My guess is something slipped into the build process that shouldn’t have.

Does a Smaller Image Start Faster?

I tested the SQL Server 2025 CU10 to CU11 and SQL Server 2022 CU27 to CU28 transitions. For each CU, I started five fresh containers and alternated which version ran first.

The table shows the median startup time for each version, with the fastest and slowest run in parentheses.

Transition Earlier CU median (range) (s) Later CU median (range) (s)
2025 CU10 to CU11 9.25 (8.05 to 9.38) 8.13 (8.04 to 9.47)
2022 CU27 to CU28 6.99 (5.86 to 7.73) 6.85 (5.84 to 7.11)

CU11’s median was 1.12 seconds lower than CU10’s. CU28’s median was 0.14 seconds lower than CU27’s. But the ranges overlap in both comparisons, so these runs don’t show a consistent startup improvement.

The Bottom Line

The key thing here is that a smaller image saves you time and space on the pull, and in my testing that’s where the benefit ends. Once the image is on the host, startup time looks the same.

That’s still a win, and it’s particularly valuable for:

  • CI/CD pipelines: runners that start clean pull the image on every run, so 159 MB less per pull adds up.
  • Kubernetes clusters: a new node has to pull the image before the first Pod can start.

Wrapping Up

The SQL Server Linux container images got about 25% smaller in SQL Server 2025 CU11 and SQL Server 2022 CU28. Startup time didn’t change much in my testing.