powershelldba.de · Uwe Janke

Enable TDE on a Single Server or in an AlwaysOn Availability Group

Enabling Transparent Data Encryption on a standalone instance is five lines of T-SQL. Enabling it on a database that lives in an Availability Group is the same five lines, plus a step that has nothing to do with T-SQL syntax and everything to do with the fact that a certificate is scoped to one instance, while AlwaysOn data movement only ever replicates the database itself. Get the order wrong and a secondary sits there "Not Synchronizing" with no obvious reason why.

The Single-Server Baseline

On a standalone instance, the sequence is straightforward: a database master key protects a certificate, the certificate protects a database encryption key, and the encryption key encrypts the actual data and log files.

USE master;
CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'A very strong password, stored in a vault';
CREATE CERTIFICATE TDE_Cert WITH SUBJECT = 'TDE Certificate for ProductionDB';

USE ProductionDB;
CREATE DATABASE ENCRYPTION KEY
    WITH ALGORITHM = AES_256
    ENCRYPTION BY SERVER CERTIFICATE TDE_Cert;

ALTER DATABASE ProductionDB SET ENCRYPTION ON;

Back up the certificate immediately, before you flip encryption on, to a location entirely separate from the database backups it protects:

BACKUP CERTIFICATE TDE_Cert
    TO FILE = 'D:\Secure\TDE_Cert.cer'
    WITH PRIVATE KEY (
        FILE = 'D:\Secure\TDE_Cert.pvk',
        ENCRYPTION BY PASSWORD = 'A different very strong password'
    );

On a single server that's the whole story. Restoring the database elsewhere means restoring this certificate first. If that's all you need, see the companion article on what TDE actually protects and the full key hierarchy.

Why an Availability Group Changes the Picture

A certificate lives in master on the instance where it was created, protected by that instance's Service Master Key. AlwaysOn data movement replicates database content: the log records that make up the primary's transactions. It does not replicate instance-level objects such as logins, linked servers, SQL Agent jobs, or certificates. That list has always excluded certificates, and it still does.

So when a database is encrypted, every secondary replica must independently possess a certificate with the exact same thumbprint as the one protecting the primary's database encryption key, before that replica can decrypt the incoming log stream. Nothing about creating the availability group or adding the database does this for you.

⚠ The failure mode is quiet, not loud. The Add Database to Availability Group wizard does not validate certificate presence on the secondaries up front. The database joins, then sits at "Not Synchronizing / Suspended" on any replica missing the certificate, with the error log reporting a decryption failure on the redo thread. Nothing about the wizard's own dialog tells you this is a certificate problem.

Correct Order of Operations: Rolling Out TDE on an AG

The rule is simple even though the consequence of skipping it is not obvious: the certificate must exist on every secondary before encryption is enabled on the primary (or before an already-encrypted database is added to the group).

  1. Create the master key and certificate on the primary, exactly as in the single-server sequence above.
  2. Back up the certificate from the primary.
  3. Restore that same certificate onto every secondary replica's master database, before touching the ALTER DATABASE ... SET ENCRYPTION ON statement.
  4. Only then enable encryption on the primary (or add the database to the availability group, if it's already encrypted).
  5. Verify encryption state on every replica, not just the primary.
-- Step 1-2: on the primary
USE master;
CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'A very strong password, stored in a vault';
CREATE CERTIFICATE TDE_Cert WITH SUBJECT = 'TDE Certificate for ProductionDB';

BACKUP CERTIFICATE TDE_Cert
    TO FILE = 'D:\Secure\TDE_Cert.cer'
    WITH PRIVATE KEY (
        FILE = 'D:\Secure\TDE_Cert.pvk',
        ENCRYPTION BY PASSWORD = 'A different very strong password'
    );

-- Step 3: on EVERY secondary, before step 4
CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'Master key password on this replica';

CREATE CERTIFICATE TDE_Cert
    FROM FILE = 'D:\Secure\TDE_Cert.cer'
    WITH PRIVATE KEY (
        FILE = 'D:\Secure\TDE_Cert.pvk',
        DECRYPTION BY PASSWORD = 'The password used when backing up the private key'
    );

-- Step 4: back on the primary, once every secondary has the certificate
USE ProductionDB;
CREATE DATABASE ENCRYPTION KEY
    WITH ALGORITHM = AES_256
    ENCRYPTION BY SERVER CERTIFICATE TDE_Cert;

ALTER DATABASE ProductionDB SET ENCRYPTION ON;

Copying a certificate to several replicas by hand is exactly the kind of repetitive, error-prone step that's worth automating. dbatools' Copy-DbaDbCertificate exports the certificate and private key from the source instance and imports it on each target in one call, which removes the chance of a typo'd password or a file that never made it to one of the secondaries:

Copy-DbaDbCertificate -Source SQL-Primary -Destination SQL-Sec1, SQL-Sec2 `
    -EncryptionPassword (ConvertTo-SecureString 'temp-export-password' -AsPlainText -Force) `
    -DecryptionPassword (ConvertTo-SecureString 'temp-export-password' -AsPlainText -Force)

Adding an Already-Encrypted Database to an Existing AG

The same rule applies in reverse. If you have a standalone database that already has TDE enabled and you're adding it to an existing availability group, restore its certificate onto every secondary before running the Add Database to Availability Group wizard (or Add-DbaAgDatabase). Adding the database first and fixing the certificate afterward just means a period of "Not Synchronizing" that a quick look at the error log will explain, but that's still an avoidable page-out at 2am.

Adding a New Replica Later

This is the scenario that catches people who got the initial rollout right: a new secondary replica joins the group months later, whether for capacity, a hardware refresh, or replacing a failed node. Automatic seeding will happily copy the encrypted database to the new replica, but it will not bring the certificate with it. Restore the certificate on the new replica first, exactly as in step 3 above, before it joins the group, or that replica will sit unsynchronized the moment data starts moving.

⚠ The worst time to discover a missing certificate is during an unplanned failover. If replica B never received the certificate and the primary fails over to it, the encrypted database on B does not become readable just because it's now the primary; it stays unreadable until the certificate is imported there. Test failover to every replica as part of validating the rollout, not just the one you expect to fail over to.

Verifying Across All Replicas

Run this on the primary and every secondary; a mismatched thumbprint or a missing row on any replica is the rollout not being finished yet, not a bug:

SELECT
    DB_NAME(dek.database_id) AS database_name,
    dek.encryption_state,        -- 3 = encrypted, 2 = encryption in progress
    dek.percent_complete,
    dek.encryptor_type,
    c.thumbprint,
    c.name AS certificate_name
FROM sys.dm_database_encryption_keys dek
JOIN sys.certificates c ON dek.encryptor_thumbprint = c.thumbprint;

dbatools' Get-DbaDbEncryption gives the same view across a list of instances in one call, which is the more practical way to confirm parity across an entire availability group instead of connecting to each replica in turn:

Get-DbaDbEncryption -SqlInstance SQL-Primary, SQL-Sec1, SQL-Sec2 |
    Select-Object SqlInstance, Database, EncryptionState, Encryptors

Certificate Backup Discipline Now Applies to the Whole Group

Everything the single-server article says about certificate backups still holds, just multiplied by the number of replicas. Losing the certificate doesn't only threaten a restore of the primary's backups; it threatens the ability of any replica that never got it to ever serve as a readable copy of that database. Keep every historical certificate for as long as backups taken under it remain in your retention policy, and store the archive with the same access-control discipline as the databases themselves, separate from where the data backups live.

Single Server vs. AlwaysOn: What Changes

StepSingle serverAlwaysOn Availability Group
Create master key & certificateOnce, on the instanceOnce, on the primary
Distribute the certificateNot applicableRestore on every secondary before enabling encryption
Enable encryptionALTER DATABASE ... SET ENCRYPTION ONSame command, but only after all secondaries have the certificate
VerifyOne instanceEvery replica; thumbprints must match
New replica joins laterNot applicableCertificate must be restored there before it joins
Certificate backup archiveOne secure locationSame archive, but every replica depends on it being complete

The Bottom Line

TDE itself does not behave any differently inside an Availability Group; the encryption, the performance characteristics, and the restore requirements are identical to the single-server case. What changes is a single operational fact that's easy to miss because nothing in the tooling forces it on you: the certificate is instance-scoped, AG data movement is database-scoped, and the two never automatically meet. Restore the certificate on every secondary before enabling encryption, do the same for every replica added afterward, and verify thumbprints across the whole group rather than trusting that the primary being encrypted means the job is done.

← Back to Blog