Restore Database Wizard Slow to Open in SSMS

The Restore Database Wizard is slow to open when msdb holds years of backup history. The wizard reads that history before it draws the first screen. The fix has three parts. Count the history, delete the old part in small steps, and keep it short from then on.

Gouache painting of a snail crossing a wooden gate with a vermilion wizard hat on the gatepost

Why the Restore Database Wizard Reads History

SQL Server writes one row to the msdb database for every backup it takes. It also keeps rows for every file inside the backup and for every restore. The Restore Database wizard reads those rows to build the list of backup sets you can restore. Nothing deletes them by default, so a busy server collects them for years.

A server with 15-minute log backups writes about 96 history rows a day for one database. That is 24 hours times 4. Across many databases and several years, the list gets long. The wizard is the first place you notice, because it is the one screen that reads all of it.

Count the History

Start by measuring. This query gives the total number of backup rows and the date of the oldest one.

SELECT COUNT(*) AS BackupRows, MIN(backup_start_date) AS OldestBackup
FROM msdb.dbo.backupset;
BackupRowsOldestBackup
2212025-11-14 13:06:02.000

This development server holds 221 rows going back to November 2025, which is small. Your numbers will differ. On a production server, a count far above this one tells you why the wizard stalls. Some advice says the history tables have no useful indexes. On SQL Server 2025, backupset has five. They are the primary key plus indexes on database name, finish date, media set and backup set ID. So an index isn’t the first thing to add.

Measure One Database

To see how history builds up, the demo database takes 40 backups to the NUL device. That is a bit bucket, so no file is written, but SQL Server still records each backup in msdb. COPY_ONLY keeps the backups out of any real backup chain.

IF DB_ID(N'RestoreWizardHistoryDemo') IS NULL CREATE DATABASE RestoreWizardHistoryDemo;
GO
DECLARE @i int = 1;
WHILE @i <= 40
BEGIN
    BACKUP DATABASE RestoreWizardHistoryDemo TO DISK = N'NUL' WITH COPY_ONLY;
    SET @i += 1;
END;
GO
SELECT COUNT(*) AS BackupRows
FROM msdb.dbo.backupset
WHERE database_name = N'RestoreWizardHistoryDemo';

The Messages tab fills with 40 groups of progress lines. The count is 40 rows. The file table backupfile holds 80 more, a data file and a log file for each backup. That is why history grows faster than the number of backups.

Quick card titled Slow Restore Wizard: Cause: the wizard reads msdb backup history. Check: count the rows in msdb.dbo.backupset. Fix: sp_delete_backuphistory with an oldest date. Go slowly: delete one month at a time. Prevent: run the cleanup every week. Tip: Delete history older than your retention.

Back Up msdb First

History deletion can’t be undone, and some teams keep that history on purpose. Ask the owners of the databases whether they need it. Then back up msdb. The backup is your way back. This statement writes a full msdb backup file, so the demo doesn’t run it. Use your own folder.

BACKUP DATABASE msdb TO DISK = N'D:\SqlBackups\msdb_before_history_cleanup.bak' WITH CHECKSUM, INIT;

Delete It in Steps

The built-in procedure for this is sp_delete_backuphistory. It deletes history older than a date, for every database on the server. Run it with an old date, so the first call touches only a little.

On a server with years of history, one call with a recent date deletes everything at once. A large delete runs as one transaction. It grows the msdb log, and it can grow tempdb too. Monthly steps keep each transaction small. Each call is a separate unit of work, so you can stop between calls. This script reads the oldest date in backupset and prints one statement for each month up to your retention. It changes nothing. You review the list and run the statements in order.

SET NOCOUNT ON;
DECLARE @keepFrom date = DATEADD(DAY, -90, CAST(SYSDATETIME() AS date));
DECLARE @first date = (SELECT CAST(MIN(backup_start_date) AS date) FROM msdb.dbo.backupset);
WITH steps AS (
    SELECT DATEADD(MONTH, 1, @first) AS cutoff
    UNION ALL
    SELECT DATEADD(MONTH, 1, cutoff) FROM steps WHERE DATEADD(MONTH, 1, cutoff) < @keepFrom
)
SELECT CONCAT(N'EXEC msdb.dbo.sp_delete_backuphistory @oldest_date = ''', CONVERT(char(10), cutoff, 120), N''';') AS StatementToRun
FROM steps
WHERE cutoff < @keepFrom
UNION ALL
SELECT CONCAT(N'EXEC msdb.dbo.sp_delete_backuphistory @oldest_date = ''', CONVERT(char(10), @keepFrom, 120), N''';')
WHERE @first < @keepFrom
ORDER BY 1
OPTION (MAXRECURSION 1000);
StatementToRun
EXEC msdb.dbo.sp_delete_backuphistory @oldest_date = ‘2025-12-14’;
EXEC msdb.dbo.sp_delete_backuphistory @oldest_date = ‘2026-01-14’;
EXEC msdb.dbo.sp_delete_backuphistory @oldest_date = ‘2026-02-14’;
EXEC msdb.dbo.sp_delete_backuphistory @oldest_date = ‘2026-03-14’;
EXEC msdb.dbo.sp_delete_backuphistory @oldest_date = ‘2026-04-14’;
EXEC msdb.dbo.sp_delete_backuphistory @oldest_date = ‘2026-05-14’;
EXEC msdb.dbo.sp_delete_backuphistory @oldest_date = ‘2026-06-14’;
EXEC msdb.dbo.sp_delete_backuphistory @oldest_date = ‘2026-07-08’;

The server here keeps 90 days. Choose your own retention. A business that must restore to any day of the last year needs a year of history. Its retention is longer.

To clean one database only, such as a dropped database, call sp_delete_database_backuphistory with its name. It removes every history row for that name.

EXEC msdb.dbo.sp_delete_database_backuphistory @database_name = N'RestoreWizardHistoryDemo';
SELECT COUNT(*) AS BackupRowsAfter
FROM msdb.dbo.backupset
WHERE database_name = N'RestoreWizardHistoryDemo';
BackupRowsAfter
0

Keep It Short

A cleanup that runs once helps for a while, and then the history grows back. Run it every week at a quiet hour. Count the rows before and after the first few runs, so you know the job does its work. A maintenance plan has a History Cleanup task for this. Without SQL Server Agent, as on Express, call the procedure from a scheduled task with sqlcmd.

A stored procedure parameter can’t be an expression, so compute the date into a variable first. The next two statements delete history older than 90 days for every database. The demo doesn’t run them, because that would delete real history on this server. A run with a date five years back deleted nothing and gave no error.

DECLARE @oldest datetime = DATEADD(DAY, -90, GETDATE());
EXEC msdb.dbo.sp_delete_backuphistory @oldest_date = @oldest;

Put the same two statements in the scheduled job.

You could argue that deleting history is risky, because the wizard builds its list from it. It does. A restore from a known file in T-SQL needs none of it, and the backup files themselves stay untouched. Delete only history older than any backup you would still use.

When the History Is Small

When the history is short and the wizard is still slow, the cause is elsewhere. Open the wizard from SSMS on another computer. If it opens fast there, look at the first computer’s own SSMS install or its list of drives.

What to Remember

Count the rows first. Delete in monthly steps from the oldest date. Keep a retention you can defend, and schedule the cleanup. Then the Restore Database Wizard opens quickly again. Run the cleanup script when you finish with the demo.

USE master;
GO
IF DB_ID(N'RestoreWizardHistoryDemo') IS NOT NULL
BEGIN
    ALTER DATABASE RestoreWizardHistoryDemo SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
    DROP DATABASE RestoreWizardHistoryDemo;
END;
EXEC msdb.dbo.sp_delete_database_backuphistory @database_name = N'RestoreWizardHistoryDemo';

A slow wizard is not a broken SSMS, it is a history nobody cleaned.

Published by Pinal Dave on SQLAuthority. More of my work at pinaldave.com.


Discover more from SQL Authority with Pinal Dave

Subscribe to get the latest posts sent to your email.

SQL Backup and Restore, SQL Scripts, SQL Server Management Studio
Previous Post
SQL SERVER – Split Comma Separated Value String in a Column Using STRING_SPLIT
Next Post
SQL SERVER – How to Find Free Log Space in SQL Server?

Related Posts

17 Comments. Leave new

  • Vasil Petrov
    May 7, 2018 6:04 pm

    This is very strange situation an I’ll never delete backup history to try to solve this issue. Backup history can be deleted after business approval

    Reply
  • True. if MSDB is huge due the backup history data and we try clean the history , I have seen for some reason TEMPDB grows during the clean up task.

    Reply
  • Haripriya Naidu
    May 8, 2018 1:55 am

    This is fantastic to know. I had the same issue. Thanks Pinal!

    Reply
  • If you have a ridiculous amount of history covering many years, the delete can take a long time…MS has no indexes on the backupset group of tables by default. I have had to add indexes and delete data one day at a time in the past for this very issue. –Kevin3NF

    Reply
    • Edward Mlynar
      July 31, 2018 8:38 pm

      This is so very true. When taking over a decade-old server where backup history has never been deleted. Executing the proc to delete the history will blow up tempdb. I had to write a script to batch-delete the history when I find myself in this situation.

      Reply
  • I had this same problem on one of my servers on which we run our own backup / checkdb / index maintenance, but have not been addressing backup history. SSMS was getting progressively slower when opening the restore wizard, taking several minutes (< 5 minutes…but still a long time) just to display the screen.

    Instead of just running the stored procedure, I decided to look more carefully at it.

    I first backed up history (just in case):

    USE mydatabase
    SELECT * INTO dbo.SQLBackupset_20190526 FROM msdb.dbo.backupset

    I then had SSMS script out the stored procedure. This worked fine. I deleted the CREATE PROCEDURE, the top level BEGIN/END, and added a SET @oldest_date = '4/1/2019'. I executed…and it ran just fine. It took just a few seconds, and had no errors.

    (I first reviewed what the stored procedure—now a query–did…just for my own knowledge.)

    What is strange: there were only a total of 8,277 rows in the table for all databases, and only 1,403 rows for the database I was trying to restore. This includes log files. Is this a lot of backups? Yes, and of course most of these are not actually available…and so preserving the history makes no sense.

    Is this so much data that it should cripple SSMS? No…not at all. In terms of rows, this isn't really a lot.

    FYI, this was on SSMS v17.9.1 against: Microsoft SQL Server 2016 (SP2-GDR) (KB4293802) – 13.0.5081.1 (X64) Jul 20 2018 22:12:40 Copyright (c) Microsoft Corporation Standard Edition (64-bit) on Windows Server 2016 Standard 10.0 (Build 14393: )

    Thank you for your post! It was very helpful. Now I’ll be sure to delete backup history regularly.

    Reply
  • Dimitris Stathoulis
    July 18, 2019 7:01 pm

    i always say you are the best. So i say it one more time. I was searching but couldn’t find the answer ,i was waiting for years to open the select button to choose the backup when trying to restore. by running your commands EXEC sp_delete_backuphistory @oldest_date = ’07/18/2019′; on msdb database ,saved my life. Thank you for your existence…

    Reply
  • Hi Pinal Dave, What do you suggest for this exact same problem – but on a brand new install of SQL Server? I create a brand new database and try to restore and the file selection dialog never appears. The database has no backup history and actually has no tables. Any ideas?
    Mike

    Reply
    • Same situation here. SQL 2017 Standard. In fact, I’m moving my live databases over using the restore wizard, that’s how new it is (select * from msdb..backupset shows 8 results for the whole server!). I can, however, connect to this server from my workstation (using SSMS 2012) and the restore wizard there only takes a few seconds to open the ‘Add Device’ dialog. This is how I restored all of the DB’s but it still confuses me why it takes so long directly on the server’s 2017 SSMS.

      Reply
  • Why does the file selection dialog take so long to appear? I tried your solution, but same problem after I start restore wizard, click on “Device” then click on the dot-dot-dot button to choose file. I find if I wait 5-10 minutes, it will appear. I’ve been doing SQL for over 20 years. This one is odd.

    Reply
  • Very useful for a development server.
    Thank you.

    Reply
  • Just posting here to give some metrics, with a database that has transaction log backups every 15 minutes.

    We had been retaining 180 days worth of history. I needed to restore a DB and found that it was taking >12 minutes to open the dialog (I actually don’t know how long, — I gave up at the 12 minute mark and killed SSMS). We dropped the history down to 30 days retention (so 8854 rows in msdb..backupset down to 1553), and then tried again. This time it took 3m12s to open the dialog. So I dropped the history down to 4 days (230 rows) and this time it only took 29s.

    Reply
  • Raphael Ferreira
    August 7, 2023 7:29 pm

    Fantastic article/post as usual. THANK you Pinal. Now… This, and subsequent comments, raise questions. Some say there was no history at all and still it would take a long time to open.
    1- Has anyone come up with the answer as to why?

    Someone mentioned indexing the table(s)/view(s)/object(s). I am most interested in this idea. So,…
    2- Any insights as to what to index, how, and also very important, any deleterious issues that could be caused by creating such index(es)? Meaning: Is it OK to go ahead and create these indexes, or because these are technically system tables meddling with them would be a no-go, maybe?

    Help appreciated. TIA, Raphael

    Reply

Leave a Reply

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

Fill out this field
Fill out this field
Please enter a valid email address.