All Products
Search
Document Center

PolarDB:Use the always-confidential database feature from a client

Last Updated:Mar 28, 2026

The always-confidential database feature encrypts sensitive columns so that only clients with the correct master encryption key (MEK) can read plaintext values. This page shows how to connect from three client types—EncJDBC, EncDB SDK, and psql—and query encrypted data.

Prerequisites

Before you begin, make sure that you have:

Sample test table

Sample table used in all examples

The examples below use a table where price, miles, and secret are encrypted columns (enc_int4, enc_float4, enc_text) and id and name are plaintext columns:

CREATE TABLE example (
    id      INTEGER,
    name    VARCHAR,
    price   enc_int4,
    miles   enc_float4,
    secret  enc_text,
    PRIMARY KEY (id)
);

Usage notes

Store your MEK securely. The always-confidential database feature does not generate, store, or back up your MEK. If you lose your MEK, you can no longer access the existing encrypted data. Back up your MEK to a secure location before you start.

Choose a client

ClientCode changes requiredWhen to use
EncJDBC (recommended)None — drop-in driver replacementJava applications that should work transparently without modifying business logic
EncDB SDKYes — call cryptor.encrypt() / cryptor.decryptXXX() explicitlyApplications that need fine-grained control over per-column encryption
psqlNoneAd-hoc queries; returns ciphertext for encrypted columns
DMS consoleNoneBrowser-based queries; returns ciphertext for encrypted columns

EncJDBC

EncJDBC is a drop-in replacement for the standard PostgreSQL JDBC driver. It automatically detects encrypted column types and handles encryption and decryption transparently—your business code requires no changes beyond the driver class and the connection URL.

Step 1: Download and install the driver

EncJDBC depends on the community PostgreSQL JDBC driver.

PolarDB for PostgreSQL versionEncDB version on clusterClient dependency package
14: 20231030 (14.9.14.0) or later1.1.13encjdbc-1.0.6.jar

Install the JAR to your local Maven repository:

mvn install:install-file \
  -DgroupId=com.alibaba.encdb \
  -DartifactId=encjdbc \
  -Dversion=1.0.6 \
  -Dpackaging=jar \
  -Dfile=<path-to-encjdbc-1.0.6.jar>
Maven 3.9.2 is required. If you use an earlier version, upgrade Maven before running this command.

Step 2: Add Maven dependencies

Add the following to the <dependencies> section of your pom.xml:

<dependency>
  <groupId>com.alibaba.encdb</groupId>
  <artifactId>encjdbc</artifactId>
  <version>1.0.6</version>
</dependency>
<!-- Bouncy Castle crypto provider -->
<dependency>
  <groupId>org.bouncycastle</groupId>
  <artifactId>bcprov-jdk15on</artifactId>
  <version>1.62</version>
</dependency>
<dependency>
  <groupId>org.bouncycastle</groupId>
  <artifactId>bcpkix-jdk15on</artifactId>
  <version>1.62</version>
</dependency>
<dependency>
  <groupId>com.alibaba.fastjson2</groupId>
  <artifactId>fastjson2</artifactId>
  <version>2.0.2</version>
</dependency>
<dependency>
  <groupId>org.postgresql</groupId>
  <artifactId>postgresql</artifactId>
  <version>42.2.23</version>
</dependency>
<dependency>
  <groupId>com.google.guava</groupId>
  <artifactId>guava</artifactId>
  <version>24.1.1-jre</version>
</dependency>
<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>druid</artifactId>
  <version>1.2.4</version>
</dependency>
<!-- jgrapht 1.4.0: versions 1.5.0+ drop Java 1.8 support -->
<dependency>
  <groupId>org.jgrapht</groupId>
  <artifactId>jgrapht-core</artifactId>
  <version>1.4.0</version>
</dependency>

Step 3: Connect and query

Warning

The sample code below is for demonstration only. Do not hardcode password or mek values in production code. Load them from environment variables or an external configuration file instead.

The connection URL uses the encjdbc:postgresql:// scheme and carries encryption parameters as query string fields:

String dbUrl = String.format(
    "encjdbc:postgresql://%s:%s/%s?mek=%s&enc_algo=%s",
    hostname, port, dbname, mek, encAlgo
);
Class.forName("com.alibaba.encdb.encjdbc.EncDriver");
Connection dbConnection = DriverManager.getConnection(dbUrl, username, password);

Data security-related parameters

Encryption parameters

The mek and other security parameters are set on the client side and transmitted to the server using envelope encryption, keeping the MEK value confidential in transit.

ParameterDefaultDescription
mek(required)Your MEK: a 32-character hex string (for example, 0x00112233445566778899aabbccddeeff). Generate one with openssl rand -hex 16, a language's built-in random function, or a third-party key management service (KMS).
enc_algoSM4_128_CBCEncryption algorithm. International: AES_128_GCM, AES_128_CBC, AES_128_ECB. ShangMi (SM): SM4_128_GCM, SM4_128_CBC, SM4_128_ECB. The CTR mode is not supported. Avoid ECB variants (AES_128_ECB, SM4_128_ECB) in production—they provide weaker security guarantees.
enc_schemeRNDEncryption scheme. RND = probabilistic encryption (recommended). DET = deterministic encryption. Ignored when enc_algo is AES_128_ECB or SM4_128_ECB.
dek_gen_modeENCLAVEHow the data encryption key (DEK) is generated. ENCLAVE = generated by the database server inside the trusted enclave. LOCAL = generated by the client.
statelesstruetrue = the MEK remains valid after the client disconnects. false = the MEK is invalidated on disconnect.

Concatenate multiple parameters with &.

Complete example

// Load credentials from environment variables in production code.
String hostname = "hostname";
String port     = "port";
String dbname   = "db";
String username = "user";
String password = "password";

// Example MEK — use a stronger, randomly generated value in production.
String mek     = "00112233445566778899aabbccddeeff";
String encAlgo = "SM4_128_CBC";

String dbUrl = String.format(
    "encjdbc:postgresql://%s:%s/%s?mek=%s&enc_algo=%s",
    hostname, port, dbname, mek, encAlgo
);
Class.forName("com.alibaba.encdb.encjdbc.EncDriver");
Connection dbConnection = DriverManager.getConnection(dbUrl, username, password);

// Create table
dbConnection.createStatement().executeUpdate("DROP TABLE IF EXISTS example");
dbConnection.createStatement().executeUpdate(
    "CREATE TABLE example " +
    "(id INTEGER, name VARCHAR, price enc_int4, miles enc_float4, secret enc_text, PRIMARY KEY (id))"
);

// Insert encrypted data — EncJDBC encrypts automatically
PreparedStatement stmt = dbConnection.prepareStatement(
    "INSERT INTO example (id, name, price, miles, secret) VALUES(?,?,?,?,?)"
);
int    price  = 1234;
float  miles  = 12.34f;
String secret = "aliyun";
stmt.setInt(1, 1);
stmt.setString(2, "name");
stmt.setInt(3, price);
stmt.setFloat(4, miles);
stmt.setString(5, secret);
stmt.execute();

// Query — EncJDBC decrypts automatically; the result set contains plaintext values
String sqlCmd = "SELECT * FROM example WHERE price > ?";
PreparedStatement query = dbConnection.prepareStatement(sqlCmd);
query.setInt(1, 100);
ResultSet rs = query.executeQuery();
while (rs.next()) {
    int    id     = rs.getInt(1);
    String name   = rs.getString(2);
    int    priceV = rs.getInt(3);
    float  milesV = rs.getFloat(4);
    String secretV = rs.getString(5);
    System.out.println(id + ", " + name + ", " + priceV + ", " + milesV + ", " + secretV);
}

Expected output:

1, name, 1234, 12.34, aliyun

Only the driver class and the URL scheme differ from standard JDBC. All other database operations—inserts, queries, prepared statements—work identically to a plain JDBC program.

EncDB SDK

EncDB SDK gives you explicit control over encryption and decryption. Use this approach when your application needs to manage ciphertext directly, for example when processing data outside of standard SQL queries.

Step 1: Download and install the SDK

PolarDB for PostgreSQL versionEncDB version on clusterClient dependency package
14: 20231030 (14.9.14.0) or later1.1.13libencdb-1.2.12.jar

Install the JAR to your local Maven repository:

mvn install:install-file \
  -DgroupId=com.alibaba.encdb \
  -DartifactId=libencdb \
  -Dversion=1.2.12 \
  -Dpackaging=jar \
  -Dfile=<path-to-libencdb-1.2.12.jar>
Maven 3.9.2 is required. If you use an earlier version, upgrade Maven before running this command.

Step 2: Add Maven dependencies

<dependency>
  <groupId>com.alibaba.encdb</groupId>
  <artifactId>libencdb</artifactId>
  <version>1.2.12</version>
</dependency>
<dependency>
  <groupId>org.bouncycastle</groupId>
  <artifactId>bcprov-jdk15on</artifactId>
  <version>1.70</version>
</dependency>
<dependency>
  <groupId>org.bouncycastle</groupId>
  <artifactId>bcpkix-jdk15on</artifactId>
  <version>1.70</version>
</dependency>
<dependency>
  <groupId>com.google.code.gson</groupId>
  <artifactId>gson</artifactId>
  <version>2.10.1</version>
</dependency>
<dependency>
  <groupId>org.postgresql</groupId>
  <artifactId>postgresql</artifactId>
  <version>42.2.23</version>
</dependency>
<dependency>
  <groupId>com.google.guava</groupId>
  <artifactId>guava</artifactId>
  <version>31.1-jre</version>
</dependency>

Step 3: Initialize the SDK and query data

Warning

The sample code below is for demonstration only. Do not hardcode password or mek values in production code. Load them from environment variables or an external configuration file instead.

EncDB SDK uses a standard PostgreSQL JDBC connection with binaryTransfer=true. After connecting, initialize an EncdbSDK object with your MEK and encryption algorithm. In most cases, the only required settings are setMek and setEncAlgo; use the defaults for everything else.

The MEK and other security parameters are set on the client side and transmitted to the server using envelope encryption, keeping the MEK value confidential in transit.

Initialize SDK-related parameters

SDK initialization parameters

ParameterDefaultDescription
Mek(required)Your MEK: a 16-byte byte[] or a 32-character hex string. Generate one with openssl rand -hex 16, a language's built-in random function, or a third-party KMS.
EncAlgoSM4_128_CBCEncryption algorithm. Same values as EncJDBC: AES_128_GCM, AES_128_CBC, AES_128_ECB, SM4_128_GCM, SM4_128_CBC, SM4_128_ECB. Avoid ECB variants in production.
EncSchemeRNDRND = probabilistic encryption. DET = deterministic encryption. Ignored when EncAlgo is AES_128_ECB or SM4_128_ECB.
DekGenModeENCLAVEENCLAVE = DEK generated by the server in the trusted enclave. LOCAL = DEK generated by the client.
SdkModeDefaultDefault supports all ciphertext data types in Basic Edition and Hardware-enhanced Edition.
Statelesstruetrue = MEK remains valid after disconnect. false = MEK is invalidated on disconnect.

Complete example

// Load credentials from environment variables in production code.
String hostname = "hostname";
String port     = "port";
String dbname   = "db";
String username = "user";
String password = "password";

// Standard JDBC connection with binary transfer enabled for encrypted column types
String dbUrl = String.format(
    "jdbc:postgresql://%s:%s/%s?binaryTransfer=true",
    hostname, port, dbname
);
Class.forName("org.postgresql.Driver");
Connection dbConnection = DriverManager.getConnection(dbUrl, username, password);

// Initialize the SDK with your MEK and encryption algorithm
// Example MEK — use a stronger, randomly generated value in production.
String mek = "00112233445566778899aabbccddeeff";
Constants.EncAlgo encAlgo = Constants.EncAlgo.SM4_128_CBC;

EncdbSDK sdk = EncdbSDKBuilder.newInstance()
        .setDbConnection(dbConnection)
        .setMek(mek)
        .setEncAlgo(encAlgo)
        .build();
Cryptor cryptor = sdk.getCryptor();

// Create table
dbConnection.createStatement().executeUpdate("DROP TABLE IF EXISTS example");
dbConnection.createStatement().executeUpdate(
    "CREATE TABLE example " +
    "(id INTEGER, name VARCHAR, price enc_int4, miles enc_float4, secret enc_text, PRIMARY KEY (id))"
);

// Insert — encrypt each sensitive value explicitly before binding
PreparedStatement stmt = dbConnection.prepareStatement(
    "INSERT INTO example (id, name, price, miles, secret) VALUES(?,?,?,?,?)"
);
int    price  = 1234;
float  miles  = 12.34f;
String secret = "aliyun";
stmt.setInt(1, 1);
stmt.setString(2, "name");
stmt.setBytes(3, cryptor.encrypt("example", "price",  price));   // table name + column name
stmt.setBytes(4, cryptor.encrypt("example", "miles",  miles));
stmt.setBytes(5, cryptor.encrypt("example", "secret", secret));
stmt.execute();

// Query — decrypt each sensitive column explicitly after reading the raw bytes
String sqlCmd = "SELECT * FROM example WHERE price > ?";
PreparedStatement query = dbConnection.prepareStatement(sqlCmd);
query.setBytes(1, cryptor.encrypt("example", "price", 100));
ResultSet rs = query.executeQuery();
while (rs.next()) {
    int    id      = rs.getInt(1);
    String name    = rs.getString(2);
    int    priceV  = cryptor.decryptInt(rs.getBytes(3));
    float  milesV  = cryptor.decryptFloat(rs.getBytes(4));
    String secretV = cryptor.decryptString(rs.getBytes(5));
    System.out.println(id + ", " + name + ", " + priceV + ", " + milesV + ", " + secretV);
}

Expected output:

1, name, 1234, 12.34, aliyun
Pass the correct table name and column name to cryptor.encrypt(). If the names do not match the column definition, the SDK cannot look up the correct data encryption key (DEK) and the operation will fail.

SDK API reference

`com.alibaba.encdb.crypto.EncdbSDKBuilder` — builder class

EncdbSDKBuilder newInstance();
EncdbSDKBuilder setDbConnection(java.sql.Connection dbConnection); // Required
EncdbSDKBuilder setKeyMgmtType(KeyMgmtType kmType);               // Required; use MYSQL_PROXY for confidential MySQL databases
EncdbSDKBuilder setMek(byte[] mek);                               // Required (16-byte byte[])
EncdbSDKBuilder setMek(String mekStr);                            // Required (32-char hex string)
EncdbSDKBuilder setEncAlgo(EncAlgo encAlgo);                      // Optional; default SM4_128_CBC
EncdbSDK        build();

`com.alibaba.encdb.EncdbSDK` — key management and secure communication

Cryptor getCryptor();

`com.alibaba.encdb.Cryptor` — encrypt and decrypt operations

encrypt() overloads accept byte[], int, long, float, double, String, BigDecimal, and Timestamp. All overloads take (tblName, colName, value) or (schemaName, tblName, colName, value).

decrypt() type-specific methods:

int         decryptInt(byte[] val);
long        decryptLong(byte[] val);
float       decryptFloat(byte[] val);
double      decryptDouble(byte[] val);
String      decryptString(byte[] val);
BigDecimal  decryptDecimal(byte[] val);
Timestamp   decryptTimestamp(byte[] val);

psql

Connect to the cluster with psql as you normally would, then run your queries. Encrypted columns return ciphertext; plaintext columns return their values normally.

For example, running SELECT * FROM example; produces output similar to:

image.png

In this output, id and name are plaintext columns. price, miles, and secret are ciphertext columns—their encrypted values are visible on the cluster, but the underlying data remains protected at all times.

DMS console

Run queries in the Data Management (DMS) console the same way you would for any PolarDB for PostgreSQL cluster.

image.png

The behavior is the same as psql: id and name appear as plaintext, while price, miles, and secret appear as ciphertext.

FAQ

What does error `0xf7070000` mean when connecting?

This error code indicates that your MEK could not be imported. Data encrypted with one MEK cannot be accessed with a different MEK. If you connect to the same always-confidential database with the same account but different MEK values across sessions, this error occurs. Use the same MEK consistently across all connections to the same database.

What's next