This episode secures database connections with Kerberos: configuring pg_hba.conf with the gss method and hostgssenc, the postgres principal and keytab, psql and JDBC connections, comparing GSSAPI with SSL, and the Kerberos authentication plugins in MySQL and MariaDB.

In episode 15 you made browsers authenticate to web servers with Kerberos tickets. The database is the next frontier — and the most vulnerable one: DB credentials are often stored in application config files, typed by hand, or even sent in the clear before an SSL session starts. This episode closes that gap for PostgreSQL and MySQL/MariaDB with GSSAPI and Kerberos.
The core is the same as before: a ticket proves identity, a keytab proves the server. The difference this time is that the service principal becomes postgres/server.example.com, and the configuration lives in files like pg_hba.conf and the server's built-in authentication plugins.
PostgreSQL supports GSSAPI authentication natively: a client holding a Kerberos ticket authenticates without a password, and if desired, the entire connection is encrypted with the Kerberos session key.
Service principal. Create a dedicated principal for the database server:
kadmin.local -q "addprinc -randkey postgres/db1.example.com"
kadmin.local -q "ktadd -k /etc/krb5.keytab postgres/db1.example.com"Tell PostgreSQL where the keytab is via the krb_server_keyfile parameter in postgresql.conf, then make sure the keytab is readable by the user running Postgres.
pg_hba.conf. Connection rules are written in /etc/postgresql/*/main/pg_hba.conf. The gss method requires GSSAPI authentication; the hostgssenc prefix mandates a GSSAPI-encrypted channel:
# GSSAPI authentication with mandatory GSSAPI encryption
hostgssenc all all 0.0.0.0/0 gss
# GSSAPI allowed, encryption optional
host all all 0.0.0.0/0 gss include_realm=0 map=krb_mapinclude_realm=0 in pg_hba.conf strips the realm so alice@EXAMPLE.COM maps to user alice. Additional mapping is done in the pg_ident.conf file with a rule like krb_map alice@EXAMPLE.COM alice.
Keytab setup and client connection. After krb_server_keyfile is set and Postgres is restarted, the client simply needs a ticket:
kinit alice
psql "host=db1.example.com dbname=appdb user=alice"psql uses the TGT to request the postgres/db1.example.com service ticket from the KDC — no password is typed or sent.
PostgreSQL offers two connection protection layers that are easy to confuse:
| Aspect | GSSAPI encryption | SSL/TLS |
|---|---|---|
| Authentication | Kerberos ticket | Certificate (optional) |
| Encryption | Kerberos session key | Server certificate |
| Trust | KDC | CA / trust store |
| Suitable for | Existing Kerberos realm | All clients |
Both can be combined: GSSAPI authentication on top of an SSL channel. The main performance implications are on encryption: GSSAPI encryption uses Kerberos cryptography (usually AES), which is light for modern servers, but for large queries any encryption layer adds latency. When the internal network is trusted, gss without hostgssenc is enough for authentication; use GSSAPI or SSL encryption only when data crosses an untrusted network or compliance requires it.
Tip
Check whether a connection actually uses GSSAPI with the query select * from pg_hba_file_rules; and look at the connection_type and auth_method columns on the matching row. To confirm the encrypted channel is active, run select ssl from pg_stat_ssl where pid = pg_backend_pid(); — a true value means GSSAPI (or SSL) encryption is running. Quick tip: hostgssenc forces encryption, host leaves it optional.
MySQL (starting from version 8.0) provides the authentication_kerberos plugin, which authenticates clients with Kerberos tickets. Enable it in my.cnf:
[mysqld]
plugin-load-add=authentication_kerberos.so
authentication_kerberos_principal_name=mysql/db1.example.comThen create a user bound to a Kerberos principal:
CREATE USER 'alice'@'%' IDENTIFIED WITH authentication_kerberos
AS 'alice@EXAMPLE.COM';Configuration. The MySQL server must use a keytab containing that principal (set via authentication_kerberos_service_keytab or the default keytab), and the client needs libkdc/GSSAPI that can read the Kerberos cache. After kinit alice, the client can log in without a password.
Limitations. This plugin only performs authentication — the connection itself is not encrypted by GSSAPI; encryption still requires MySQL TLS. Platform support is also limited (most mature on Linux with MIT GSSAPI), and the client used must support the mechanism, e.g. via mysql_config_editor or a connector that understands Kerberos.
MariaDB approaches the same problem through the gssapi plugin, which offers deeper integration: Kerberos authentication and GSSAPI-based connection encryption. Enable it by loading the plugin:
[mariadb]
plugin_load_add=auth_gssapi
gssapi_principal_name=mariadb/db1.example.com
gssapi_keytab=/etc/krb5.keytabUser mapping. Create the user and map it to a Kerberos principal:
CREATE USER 'alice'@'%' IDENTIFIED VIA gssapi AS 'alice@EXAMPLE.COM';Connection strings. From the client, the connection happens without a password once a ticket is available. In an ODBC DSN or connector, just select the GSSAPI mechanism and make sure KRB5CCNAME points to the ticket cache:
kinit alice
mariadb --user=alice --host=db1.example.comOne practical difference: MariaDB requires GSSAPI encryption when gssapi_encryption is enabled, so connection data is protected too — an advantage the MySQL plugin doesn't have.
Java applications on an application server use JDBC drivers, and JDBC knows Kerberos through JAAS (Java Authentication and Authorization Service). The connection uses a special URL:
jdbc:postgresql://db1.example.com:5432/appdb?gssEncMode=require&user=alice&kerberosServerName=postgresFor MySQL, it's similar, with parameters that enable Kerberos on the connector.
Keytab vs ticket cache. The application server can use either credential source. A ticket cache suits interactive sessions; a keytab suits daemons that run continuously (using kinit -kt before the application starts). Relying on the cache is risky: when the ticket expires, the application loses connections. A common solution is keytab + scheduled renewal, or JAAS with a declared principal and keyTab.
Connection pooling. Connection pools (like HikariCP) complicate Kerberos: old pooled connections hold GSSAPI contexts from old tickets. After the ticket changes, pooled connections can fail. Best practice: set the maximum connection age slightly below the ticket lifetime, or validate connections periodically and discard failing ones.
Troubleshooting. The most common failure pattern: GSSException: Failure unspecified at GSS-API level means the GSSAPI context failed to build — check the server keytab, the principal name, and KRB5CCNAME. Principal not found points to realm mapping. Start with klist on both sides, then check pg_hba.conf to make sure the gss line actually matches the client's address.
Important
The key difference between authentication and encryption: the MySQL Kerberos plugin only authenticates, while PostgreSQL and MariaDB GSSAPI can also encrypt the connection. Don't assume a Kerberos login means encrypted data — check the hostgssenc (PostgreSQL) or gssapi_encryption (MariaDB) configuration, and enable TLS when neither is available.
This episode closed the last gate that was often guarded by a password: the database. You authenticated to PostgreSQL via the gss method in pg_hba.conf with the postgres/db1.example.com principal and krb_server_keyfile, compared GSSAPI encryption with SSL, enabled the authentication_kerberos plugin in MySQL and gssapi in MariaDB, then connected Java applications via JDBC/JAAS with a keytab or ticket cache.
Key takeaways:
authentication_kerberos only proves identity; use hostgssenc (PostgreSQL), gssapi_encryption (MariaDB), or TLS to protect data on the wire.include_realm=0 and pg_ident.conf connect the alice@EXAMPLE.COM principal to the database-managed user alice.In episode 17 we lay the directory foundation: LDAP and Kerberos integration — from LDAP as the KDC's principal backend to SASL/GSSAPI binds in OpenLDAP. See you there!