All Products
Search
Document Center

PolarDB:Transparent data encryption (TDE)

Last Updated:Mar 28, 2026

Transparent Data Encryption (TDE) encrypts all user data at the database layer — data files, write-ahead logs (WAL), and the key management file on shared storage. Authenticated users access data transparently without any changes to application code or configurations. Unauthorized users who bypass the database and access the storage layer directly see only encrypted bytes.

TDE helps you meet encryption-at-rest requirements for the following compliance standards:

China: Cryptography Law of the People's Republic of China (effective January 1, 2020), Classified Protection of Cybersecurity (GB/T 22239-2019)

International: Payment Card Industry Data Security Standard (PCI DSS), Health Insurance Portability and Accountability Act (HIPAA), General Data Protection Regulation (GDPR), California Consumer Protection Act (CCPA), Sarbanes-Oxley Act (SOX)

Supported versions

TDE is available on PolarDB for PostgreSQL clusters running the following engine versions:

Engine versionMinimum minor version
PostgreSQL 112.0.11.2.1.0
PostgreSQL 142.0.14.5.1.1
PostgreSQL 162.0.16.9.6.0
PostgreSQL 172.0.17.6.4.0
PostgreSQL 182.0.18.0.1.0
TDE is not supported on PolarDB for PostgreSQL Distributed Edition clusters.

To check your minor engine version, run SHOW polardb_version; or view it in the console. If your version does not meet the requirement, upgrade the minor engine version.

Limitations

  • TDE is not supported on PolarDB for PostgreSQL Distributed Edition clusters.

Key concepts

TermDescription
Key Encryption Key (KEK)A key that encrypts another key. The KEK is derived from an external passphrase command and is never stored on disk.
Memory Data Encryption Key (MDEK)The root data encryption key, randomly generated by pg_strong_random and kept only in memory.
Table Data Encryption Key (TDEK)Derived from the MDEK using the HMAC-based Key Derivation Function (HKDF). Encrypts table data.
WAL Data Encryption Key (WDEK)Derived from the MDEK using HKDF. Encrypts write-ahead log data.
Hash-based Message Authentication Code (HMAC)A keyed-hash algorithm used for integrity verification. In TDE, a passphrase is processed with SHA-512 to produce 64 bytes: the first 32 bytes become the KEK, the last 32 bytes become the HMACK.
Encode Memory Data Encryption Key (ENCMDEK)An encrypted data encryption key that is stored in memory. Generated by encrypting the MDEK with the KEK.
KEK_HMACA digest generated from the ENCMDEK and HMACK using the HMAC algorithm. Stored alongside the ENCMDEK and used as verification information when a key is reverted.

How it works

TDE operates through three coordinated modules: key management, encryption, and decryption.

Key management

Key structure

TDE uses a two-layer key hierarchy:

  • Top layer — KEK: Protects the data encryption key. Retrieved externally on each startup via the polar_cluster_passphrase_command parameter (for example, from a Key Management Service (KMS) or, for testing, echo passphrase).

  • Bottom layer — data encryption keys (MDEK, TDEK, WDEK): Perform the actual encryption of data pages and WAL records.

The ENCMDEK and KEK_HMAC are saved on shared storage in the global/kmgr file (KmgrFileData structure), so every node in the cluster — primary and read-only — can recover the data encryption keys at startup. This file is created during database initialization (initdb), which means standby nodes can obtain it via pg_basebackup.

When the cluster is running, key material is held in process memory:

static keydata_t keyEncKey[TDE_KEK_SIZE];
static keydata_t relEncKey[TDE_MAX_DEK_SIZE];
static keydata_t walEncKey[TDE_MAX_DEK_SIZE];
char *polar_cluster_passphrase_command = NULL;
extern int data_encryption_cipher;

Key initialization

Keys are generated once during database initialization:

Key encryption process
  1. Run polar_cluster_passphrase_command to get the 32-byte KEK and 32-byte HMACK.

  2. Call the OpenSSL random number generator to produce the MDEK.

  3. Derive the TDEK from the MDEK using HKDF (OpenSSL).

  4. Derive the WDEK from the MDEK using HKDF (OpenSSL).

  5. Encrypt the MDEK with the KEK to produce the ENCMDEK.

  6. Generate the KEK_HMAC from the ENCMDEK and HMACK using the HMAC algorithm.

  7. Write the ENCMDEK, KEK_HMAC, and other KmgrFileData fields to the global/kmgr file.

The KmgrFileData structure on disk:

typedef struct KmgrFileData
{
    /* version for kmgr file */
    uint32      kmgr_version_no;

    /* Are data pages encrypted? Zero if encryption is disabled */
    uint32      data_encryption_cipher;

    /*
     * Wrapped Key information for data encryption.
     */
    WrappedEncKeyWithHmac tde_rdek;
    WrappedEncKeyWithHmac tde_wdek;

    /* CRC of all above ... MUST BE LAST! */
    pg_crc32c   crc;
} KmgrFileData;

Key decryption (on restart)

When the database restarts or recovers from a crash, TDE reconstructs the data encryption keys from the stored ciphertext:

Key decryption process
  1. Read the global/kmgr file to get the ENCMDEK and KEK_HMAC.

  2. Run polar_cluster_passphrase_command to get the KEK and HMACK.

  3. Generate KEK_HMAC' from the ENCMDEK and HMACK using HMAC. If it matches the stored KEK_HMAC, proceed. If not, return an error.

  4. Decrypt the ENCMDEK with the KEK to recover the MDEK.

  5. Derive the TDEK from the MDEK using HKDF (deterministic — same MDEK always produces the same TDEK).

  6. Derive the WDEK from the MDEK using HKDF (deterministic — same MDEK always produces the same WDEK).

Key rotation

Key rotation re-encrypts the MDEK under a new KEK without changing the MDEK itself, so all existing data remains readable after rotation. The process updates the global/kmgr file with the new ENCMDEK and KEK_HMAC.

Key rotation process
  1. Read the global/kmgr file to get the ENCMDEK and KEK_HMAC.

  2. Run polar_cluster_passphrase_command to get the current KEK and HMACK (64 bytes total).

  3. Generate KEK_HMAC' from the ENCMDEK and HMACK using HMAC. If it matches the stored KEK_HMAC, proceed. If not, return an error.

  4. Decrypt the ENCMDEK with the KEK to recover the MDEK.

  5. Run polar_cluster_passphrase_command again to get the new KEK (new_KEK) and new HMACK (new_HMACK).

  6. Encrypt the MDEK with new_KEK to produce new_ENCMDEK.

  7. Generate new_KEK_HMAC from new_ENCMDEK and new_HMACK using HMAC.

  8. Write new_ENCMDEK, new_KEK_HMAC, and other KmgrFileData fields to the global/kmgr file.

Encryption

All user data is encrypted at the page level using AES-128 or AES-256. AES-256 is used by default.

Each data page is encrypted with a unique initialization vector (IV) derived from the (page LSN, page number) pair. This ensures that encrypting the same plaintext at different times produces different ciphertext.

The page header structure:

typedef struct PageHeaderData
{
    /* XXX LSN is member of *any* block, not only page-organized ones */
    PageXLogRecPtr pd_lsn;      /* LSN: next byte after last byte of xlog
                                 * record for last change to this page */
    uint16      pd_checksum;    /* checksum */
    uint16      pd_flags;       /* flag bits, see below */
    LocationIndex pd_lower;     /* offset to start of free space */
    LocationIndex pd_upper;     /* offset to end of free space */
    LocationIndex pd_special;   /* offset to start of special space */
    uint16      pd_pagesize_version;
    TransactionId pd_prune_xid; /* oldest prunable XID, or zero if none */
    ItemIdData  pd_linp[FLEXIBLE_ARRAY_MEMBER]; /* line pointer array */
} PageHeaderData;

Three fields in each page header are intentionally left unencrypted:

FieldReason
pd_lsnRequired as the IV input for encryption and decryption
pd_flagsThe 0x8000 bit indicates whether the page is encrypted; leaving it unencrypted allows backward-compatible reading of plaintext pages and supports enabling TDE on existing clusters
pd_checksumChecksum is verified against the ciphertext, so it must remain readable before decryption

Encrypted file locations

All files that contain user data are encrypted. These include files in the following subdirectories of the data directory:

  • base/

  • global/

  • pg_tblspc/

  • pg_replslot/

  • pg_stat/

  • pg_stat_tmp/

Encryption timing

Encryption happens immediately before the checksum is calculated, just before a page is written to disk. Even when checksums are disabled, PageSetChecksumCopy or PageSetChecksumInplace is always called — TDE hooks into this step to ensure every byte written to storage is encrypted.

Decryption

When a page is read from storage into memory, decryption runs immediately after the checksum is verified. Even when checksums are disabled, PageIsVerified is always called — TDE hooks into this step to ensure the data in memory is always in plaintext.