As mentioned previously, the process of setting up TDE (Setting up Transparent Data Encryption (TDE)) is the same whether you’ve just set up a new database, or whether you’re working with a live database. Once you turn encryption on SQL Server will begin the process of encrypting any data in your database. Be that 1 row, or be that terabytes of data.
I’m going to load up my database with about 1 GB of data so we can get an idea of how long this process takes.
CREATE DATABASE TestTDE; USE TestTDE; CREATE TABLE dbo.SomeData(Id INT IDENTITY(1,1), SomeText VARCHAR(255)); INSERT INTO dbo.SomeData (SomeText) SELECT TOP 1000000 ('XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX') FROM sys.objects a CROSS JOIN sys.objects b CROSS JOIN sys.objects c CROSS JOIN sys.objects d; GO 10
I then go through all the steps mentioned previously to set up encryption:
Setting up Transparent Data Encryption (TDE)
After the last step:
ALTER DATABASE TestTDE SET ENCRYPTION ON;
I run a query to report the progress:
DECLARE @state tinyint; DECLARE @encyrption_progress TABLE(sample_time DATETIME, percent_complete DECIMAL(5,2)) SELECT @state = k.encryption_state FROM sys.dm_database_encryption_keys k INNER JOIN sys.databases d ON k.database_id = d.database_id WHERE d.name = 'TestTDE'; WHILE @state != 3 BEGIN INSERT INTO @encyrption_progress(sample_time, percent_complete) SELECT GETDATE(), percent_complete FROM sys.dm_database_encryption_keys k INNER JOIN sys.databases d ON k.database_id = d.database_id WHERE d.name = 'TestTDE'; WAITFOR delay '00:00:01'; SELECT @state = k.encryption_state FROM sys.dm_database_encryption_keys k INNER JOIN sys.databases d ON k.database_id = d.database_id WHERE d.name = 'TestTDE'; END SELECT * FROM @encyrption_progress;
I’m sampling every second, let’s look at the results:
You can see that the encryption took about 30 seconds to complete for (just under) 1GB of data. This isn’t intended to be a formal benchmark, but rather just to give you an idea of the order of magnitude of time this might take to encrypt your own databases.
Let’s say – just for the same of argument – that this scaled up linearly on a given system and you wanted to encrypt a 1TB database. Then it might take as long as 500 minutes (8 hours and 20 minutes).
The encryption occurs as a background process, but it will take some resources while it runs, so if you are implementing this against a system with large databases where performance is critical then you will want to either run it in a period of quiet – or down time, or you will want to monitor to check that encryption isn’t impacting your system too much. Experience suggests that it shouldn’t be a problem unless your server is already under strain.
There are a few things to look out for if you are monitoring during the background encryption process:
- CPU and IO, both these could take a hit
- You may want to look out for blocking caused by encryption, you can do this by checking the sys.dm_tran_locks view where the resource_subtype is “ENCRYPTION_SCAN”
- Monitor transaction log usage with DBCC LOGINFO. While the encryption scanner is running the transaction log can’t be truncated and VLFs marked for re-use. This could mean the transaction log might grow larger than normal, so you need to watch out if you are constrained for disk space.
What if you run into any performance problems during the scan?
First things first – DON’T TURN ENCRYPTION OFF!
If you turn encryption off, i.e.
ALTER DATABASE TestTDE SET ENCRYPTION OFF;
This isn’t going to stop the encryption scan, rather it’s just going to change direction. So now it will be decrypting everything it’s just encrypted, that’s likely to have just as much impact, and then sooner or you’re going to have to start again.
There is no “ALTER DATABASE TestTDE SET ENCRYPTION PAUSE;” command. There is however a trace flag (5004) that achieves the same thing.
If you enable the trace flag it will disable the encryption scanner:
When you do so, if you then query dm_database_encryption_keys you will see the database is set to a state of 2 (Encryption in progress) and the percent_complete column will show zero – as nothing is actually currently in progress.
When you wish to begin the scan again, you need to disable the traceflag and then set encryption on again (even though it’s not actually off):
DBCC TRACEOFF(5004,-1); ALTER DATABASE TestTDE SET ENCRYPTION ON;
When you do this the scanner will pick up where it left off, i.e. if it had got to 50%, it will then continue from there.
It’s important to note that the traceflag doesn’t actually turn TDE off. In fact if you add new data, or update data and it get’s written to disk while the traceflag is enabled, the data will still become encrypted. It just stops the background process of converting all the data already on disk.
If performance impact is an issue for you with the scanning process, you can use the traceflag to incrementally run the scan out of hours, pausing it when you want to ensure maximum performance of your systems.
The traceflag seems to exist for internal use by SQL if the encryption scanner runs into a problem, for instance if it encounters corruption in your database files then it will halt and the traceflag will be enabled.
This could be useful to know if you find you tried to turn TDE on for a database but it’s stuck at “Encryption in Progress” but the percent_complete remains set to Zero. Check to see if the trace flag is enabled, and if you didn’t enable it then you may want to check for corruption in your database.
More Articles on TDE
What is Transparent Data Encryption?
Setting up Transparent Data Encryption (TDE)
Understanding Keys and Certificates with Transparent Data Encryption (TDE)
How Secure is Transparent Data Encryption (TDE) – and How to Prevent Hacking
10 thoughts on “Encrypting an existing database with TDE”
There is a way to pause you encryption operation, say during a period of heavy load on the server — >
ALTER DATABASE SET ENCRYPTION SUSPEND;
Thanks – I see that was added in SQL 2019, I hadn’t heard of it before. Really good to know.