Updating SQL Server: CUs, GDRs and servicing branches
Categories:
12 minute read
Since SQL Server 2017, Microsoft no longer releases Service Packs. Only cumulative updates (CUs) and security fixes (GDRs) remain.
An instance follows one of two branches: the GDR branch, which receives security fixes only, or the CU branch, which receives every fix, security included. Installing a CU moves the instance to the CU branch.
Choose the CU branch, and always install the highest build available for your branch. It is often a “CU + GDR”, more recent than the latest CU.
You can configure Microsoft Update to automate SQL Server updates through Windows Update.
This page describes the servicing model of SQL Server 2017 and later, on Windows. The build numbers quoted are real and dated 12 September 2026.
CUs and GDRs
Microsoft dropped Service Packs with SQL Server 2017, when it adopted the Modern Servicing Model. Two types of updates remain:
| Type | Content | Frequency |
|---|---|---|
| CU, Cumulative Update | every fix, improvement and enhancement since the release of the version, security included | every month for the first year, then every two months until the end of mainstream support (five years) |
| GDR, General Distribution Release | security fixes and critical fixes | whenever a security fix is released, with no fixed schedule |
CUs are cumulative: each one contains all the previous ones. You can go straight from RTM to the latest CU without installing the ones in between.
When mainstream support ends, Microsoft stops releasing CUs. The version then receives only GDRs, until the end of extended support:
| Version | Latest CU released | End of mainstream support | End of extended support |
|---|---|---|---|
| SQL Server 2017 | CU31 (September 2022), the last one | 11 October 2022 | 12 October 2027 |
| SQL Server 2019 | CU32 (February 2025), the last one | 28 February 2025 | 8 January 2030 |
| SQL Server 2022 | CU26 (July 2026) | 11 January 2028 | 11 January 2033 |
| SQL Server 2025 | CU8 (August 2026) | 6 January 2031 | 6 January 2036 |
The two servicing branches
flowchart LR
RTM["RTM"] --> GDR1["GDR"]
GDR1 --> GDR2["Next GDR"]
RTM --> CU1["CU1"]
CU1 --> CUN["CU2 … CUn"]
CUN --> CUGDR["CUn + GDR"]
GDR1 -. "more recent CU + GDR" .-> CUGDRFrom RTM onwards, each version splits into two branches:
- the GDR branch, which receives only security fixes and critical fixes;
- the CU branch, which receives those same fixes and all the others.
As soon as you install a CU, the instance moves to the CU branch and stays there. Going back to the GDR branch would mean uninstalling every CU. Nobody has a reason to do so, since the CU branch already contains every security fix.
Moving from the GDR branch to the CU branch is possible, but not with just any CU. The CU you install must contain the security fixes of the GDR already in place, so it must have been released on the same day or later. Take the most recent build of the CU branch. A CU older than the installed GDR is rejected by the installer, with the message “There are no SQL Server instances or shared features that can be updated on this computer”.
| Policy | Branch | Use case |
|---|---|---|
| All fixes | CU | Microsoft’s recommendation, the general case |
| Security only | GDR | a software vendor that certifies its application on one specific build only, an environment where any functional change is forbidden |
I recommend the CU branch. The RTM of a version contains bugs fixed in the first CUs, and an instance that stays on the GDR branch will never receive those fixes.
Reading the build number
The SERVERPROPERTY function returns the build, the CU level and the matching KB article:
-- Version, update level and KB article of the instance
SELECT SERVERPROPERTY('ProductVersion') AS version, -- 16.0.4265.3
SERVERPROPERTY('ProductLevel') AS product_level, -- RTM
SERVERPROPERTY('ProductUpdateLevel') AS cu, -- CU26
SERVERPROPERTY('ProductUpdateReference') AS kb, -- KB5093420
SERVERPROPERTY('Edition') AS edition;
ProductLevel stays at RTM on an up-to-date instance: it reports the Service Pack, and there are none any more. The CU level is in ProductUpdateLevel, which is NULL as long as no CU is installed.
The third group of digits in the build tells you the branch. Its value depends on the version:
| Version | RTM | GDR branch | CU branch |
|---|---|---|---|
| SQL Server 2017 (14.0) | 14.0.1000.169 | 14.0.2xxx | 14.0.3xxx |
| SQL Server 2019 (15.0) | 15.0.2000.5 | 15.0.2xxx | 15.0.4xxx |
| SQL Server 2022 (16.0) | 16.0.1000.6 | 16.0.1xxx | 16.0.4xxx |
| SQL Server 2025 (17.0) | 17.0.1000.7 | 17.0.1xxx | 17.0.4xxx |
For 2019, 2022 and 2025, a third group in 4xxx means CUs have been applied. SQL Server 2017 is the exception, with CUs in 3xxx. So read the build against the RTM of its own version.
Installing the highest build of your branch
When a security fix comes out after a CU, Microsoft releases a build for each branch on the same day. This is what was available for SQL Server 2019 on 14 June 2022:
| Build | Name | Date | Content |
|---|---|---|---|
15.0.4223.1 | CU16 | 18 April 2022 | latest CU on that date, without the June security fix |
15.0.4236.7 | CU16 + GDR | 14 June 2022 | CU16 plus the June security fix, for the CU branch |
15.0.2095.3 | GDR | 14 June 2022 | the June security fix, for the GDR branch |
An administrator looking for “the latest CU” the next day installed CU16 and was left without the June fix. According to the Microsoft documentation, a CU whose build number is higher than that of a CU + GDR contains its security fixes. The practical rule is to install the highest build released for your branch, whatever its name.
Limits of the CU number
SQL Server 2019 received its last CU, CU32, on 27 February 2025. The CU branch keeps receiving security fixes, under the same name:
| Build | Name | Date |
|---|---|---|
15.0.4430.1 | CU32 | 27 February 2025 |
15.0.4455.2 | CU32 + GDR | 11 November 2025 |
15.0.4480.2 | CU32 + GDR | 14 July 2026 |
15.0.4490.9 | CU32 + GDR | 8 September 2026 |
Two instances that both show CU32 in ProductUpdateLevel can be a year and a half apart in security fixes. Compare the full build number.
Withdrawn CUs
CU7 for SQL Server 2019 (15.0.4063.15, 2 September 2020) is marked “Removed” in the SQL Server 2019 build list. It is rare, but it justifies waiting a few days to a few weeks before installing a CU in production, and testing it on a pre-production server first.
Finding the right build
| Source | Type | Use |
|---|---|---|
| Latest updates and version history for SQL Server | Microsoft Learn | latest GDR, latest CU and latest CU + GDR for each supported version, with build, KB and date |
| SQL Server yyyy build versions page, for example SQL Server 2022 | Microsoft Learn | the full history of one version, CU branch and GDR branch listed separately |
| SQLServerBuilds.xlsx | Microsoft | every build since SQL Server 2005, with the detailed fix list of each build |
| sqlserverbuilds.blogspot.com | community | the same information, one table per version, from the most recent build to the oldest |
The method:
- Get the build of the instance with the query above.
- Open the build list for its version, and find the row for that build.
- Move up to the most recent build of the same branch.
- Follow the KB link, which leads to the download page.
The community site is not a Microsoft publication (and it carries a lot of advertising these days). Check the build and the KB on Microsoft Learn before downloading.
Distribution channels
| Channel | Use |
|---|---|
| KB page and Microsoft Download Center | manual download, you choose when |
| Microsoft Update | standalone server or small estate |
| WSUS, Microsoft Update Catalog | centrally managed estate |
Windows Update only offers SQL Server updates once you opt in to Microsoft Update, which covers Microsoft products other than Windows. On Windows Server 2019 and later, the setting is under Settings > Windows Update > Advanced options > Receive updates for other Microsoft products. Without it, a server that is fully patched on the Windows side has never received a SQL Server fix.
An update received through Microsoft Update installs unattended, updates every SQL Server component and restarts the service. On a production server, enable Microsoft Update to be notified, and choose the installation time yourself: the Configure Automatic Updates Group Policy setting, option Auto download and notify for install, downloads without installing.
New instances and Microsoft Update
The automatic channel of Microsoft Update only offers the CU + GDR version of a security fix to instances that already have a CU. An instance still at RTM receives the GDR version, and moves to the GDR branch without anyone deciding it. WSUS will not bring it back to the CU branch: you have to do it by hand. The details are in Updates to the Microsoft Update detection logic for SQL Server servicing.
So install the latest build of the CU branch right after installing SQL Server, before enabling Microsoft Update.
Applying an update to a standalone instance
Before
- Take a full backup of every database, system databases included, to a location other than the server. A virtual machine snapshot does not replace a SQL Server backup.
- Run
DBCC CHECKDBon every database. - Read the KB page of the update, especially the known issues section.
- Warn the users and disable the SQL Server Agent jobs.
- Check disk space: the package weighs around 500 MB to 1 GB, and the installer needs room for its temporary files.
- Write down the starting build.
During
Run the package as administrator. A CU package contains the updates for every component of the version, but only updates the ones that are installed. If you add a component later, Analysis Services for example, apply the CU again.
The instance is unavailable during the operation. Allow about twenty minutes on a simple instance, restart included. Restart the server if the installer asks for it.
After
-- The build must match the one on the KB page
SELECT SERVERPROPERTY('ProductVersion') AS version,
SERVERPROPERTY('ProductUpdateLevel') AS cu;
-- Databases that are not online
SELECT name, state_desc
FROM sys.databases
WHERE state_desc <> 'ONLINE';
-- Upgrade script messages in the error log
EXEC sys.xp_readerrorlog 0, 1, N'upgrade';
Then re-enable the Agent jobs and check a real application process.
Restarting the service has side effects worth knowing:
| Effect | Consequence |
|---|---|
tempdb is recreated | it starts again from its configured initial size. Left at the defaults, it goes through all its growth again. |
| Cumulative DMVs are reset | sys.dm_os_wait_stats, sys.dm_io_virtual_file_stats and the others start again from zero. Capture them beforehand if you need them. |
| The plan cache is cleared | the first executions recompile and run slower. |
| Query Store is kept | it is stored in each user database and survives the restart. |
If something goes wrong
A CU is uninstalled from Control Panel > Programs and Features > View installed updates, under the entry for the SQL Server version. The instance goes back to the previous build. On Linux, you roll the mssql-server package back to its previous version. The backup taken before the operation remains the fallback if uninstalling is not enough.
Updating an Always On availability group
On an availability group, you update one replica at a time, with a single manual failover. Microsoft describes the procedure in Upgrade availability group replicas:
- Back up every database in the group and run
DBCC CHECKDB. - Set the automated backup preference to the primary replica only, and remove automatic failover from the synchronous-commit replicas.
- Update the asynchronous-commit secondary replicas, then the remote synchronous-commit secondaries, then the local synchronous-commit secondaries.
- Check that the target secondary is
SYNCHRONIZED, then fail over to it manually. - Update the former primary replica.
- Restore automatic failover and, if you wish, fail back to the original primary replica.
The WSFC cluster has a separate resource group, named Cluster Group in PowerShell and shown under Cluster Core Resources in Failover Cluster Manager. It holds the cluster name and IP address, and the witness (file share, cloud or disk). This group is owned by one node, which is not necessarily the node of the availability group’s primary replica.
Before updating a secondary replica, check which node owns this group. If it is the node you are about to update, move the group to the primary replica’s node. Check again after the failover, before updating the former primary replica.
# Node that owns the cluster core resources
Get-ClusterGroup -Name "Cluster Group"
# Move them to the node hosting the primary replica
Move-ClusterGroup -Name "Cluster Group" -Node PRIMARY-NODE
Restarting or disconnecting a node triggers a new quorum arbitration against the witness. On a two-node cluster with a witness, the primary replica’s node can lose that arbitration: its cluster service stops, and the availability group goes offline even though that node was never touched. Such cases are described on Microsoft Q&A and by Josh the Coder, and I have run into it at a client. With the core resources on the primary replica’s node, the node being updated holds neither the cluster name nor the witness when it restarts.
Never update the primary replica first. An updated primary replica can no longer send its transaction log to secondaries still on an earlier version: synchronisation stops, and the databases are exposed to data loss.
-- Synchronisation state of each database, per replica
SELECT ag.name AS availability_group,
ar.replica_server_name AS replica,
DB_NAME(drs.database_id) AS database_name,
drs.synchronization_state_desc AS state
FROM sys.dm_hadr_database_replica_states AS drs
JOIN sys.availability_replicas AS ar ON ar.replica_id = drs.replica_id
JOIN sys.availability_groups AS ag ON ag.group_id = drs.group_id
ORDER BY availability_group, replica, database_name;
How often to check
For a server with no particular requirements, a quarterly check is enough:
- Get the installed build.
- Compare it with the highest build released for its branch.
- If the gap is more than two CUs, schedule a maintenance window.
A GDR that fixes a remotely exploitable vulnerability does not wait for the quarter. The KB page of each GDR links to the matching CVE, which lets you judge.
Do
- Choose the CU branch, unless a vendor constraint says otherwise.
- Install the highest build of the branch, CU + GDR included.
- Read the full build number, and
ProductUpdateLevelrather thanProductLevel. - Enable Microsoft Update or WSUS, while choosing when the installation happens.
- Take a backup and run
DBCC CHECKDBbefore every update.
Avoid
- Looking for a Service Pack for SQL Server 2017 or later.
- Comparing CU numbers to decide which instance is the most up to date.
- Leaving a new instance at RTM with Microsoft Update enabled.
- Installing a CU in production on the day it is released.
- Updating the primary replica of an availability group before its secondaries.