Shifting the credential paradigm from static to dynamic, configuring PostgreSQL and MySQL connections in OpenBao, writing database roles with creation statements and TTLs, and retrieving short-lived credentials.

In episode 3 you stored static secrets in the KV engine — application passwords that remain valid indefinitely. Episode 4 brings a bigger paradigm shift: dynamic credentials. Instead of storing passwords that stay valid for years, OpenBao creates database users and passwords on-demand, with short lifetimes, then revokes them on its own.
This is one of OpenBao's most impactful features, and in this episode you will practice it directly with PostgreSQL or MySQL.
To understand the value of dynamic credentials, first compare the two approaches:
| Aspect | Static Credentials | Dynamic Credentials |
|---|---|---|
| Validity period | Unlimited or very long | Short TTL, e.g. 1 hour |
| Leak risk | High — once leaked, usable by others for a long time | Low — when leaked, the validity has already passed |
| Revocation | Manual, and you must know every place they are used | Automatic by OpenBao when the lease expires |
| Rotation | Requires a process and downtime | Not needed — each request produces new credentials |
| Usage trail | Difficult to track | Every credential has a recorded lease ID |
The key point: with dynamic credentials, no password lingers on a server for long. When an application needs database access, it asks OpenBao, gets credentials valid for only a few hours, uses them, and the credentials disappear. If a configuration file leaks into the internet's digital dumpster, the credentials inside are already useless.
This practice requires a database that OpenBao can manage — meaning OpenBao must have the rights to create and drop roles. In PostgreSQL, set up one dedicated admin user for OpenBao:
CREATE ROLE "bao-admin" WITH LOGIN PASSWORD 'strong-admin-password';
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO "bao-admin";
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO "bao-admin";This is the user OpenBao will use to create temporary users. In MySQL, the concept is similar: OpenBao needs a user with CREATE USER, GRANT, and REVOKE privileges. The same principle applies — OpenBao acts as the intermediary that manages credentials on behalf of applications.
First, enable the database secrets engine:
bao secrets enable database
bao secrets listThen register the connection to your database. This is where OpenBao learns how to reach the database and which admin credentials to use:
bao write database/config/my-db \
plugin_name=postgresql-database-plugin \
connection_url="postgresql://{{username}}:{{password}}@db.internal:5432/appdb" \
username="bao-admin" \
password="strong-admin-password" \
allowed_roles="my-role"bao write database/config/my-db stores the connection configuration. The allowed_roles="my-role" part limits which roles may use this connection — important security so that a single connection cannot be used for unauthorized roles. The username and password placeholders inside the URL are replaced automatically by OpenBao.
Once the connection is registered, create a role that defines the access rights and lifetime of the credentials:
bao write database/roles/my-role \
db_name=my-db \
creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; \
GRANT SELECT, INSERT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \
default_ttl="1h" \
max_ttl="24h"creation_statements is the SQL that OpenBao executes every time it creates new credentials — note the name, password, and expiration placeholders that OpenBao fills in automatically. default_ttl="1h" sets the credentials to be valid for one hour; max_ttl="24h" limits the maximum renewal to 24 hours.
Important
max_ttl is a safety net: even if a lease is requested to be renewed over and over, it will never pass this limit. With short TTLs, the blast radius of a credential leak stays small even if there is a bug in the application.
When an application needs database access, it simply requests credentials from the role:
bao read database/creds/my-roleOpenBao immediately executes the creation statements in PostgreSQL, creates a temporary user, and returns the result:
Key Value
--- -----
lease_id database/creds/my-role/z8lX3e2KcV9WbN...
lease_duration 1h
password m7xK2pL9qR4sT8vW
username v-my-role-3fB2dKzL9pR7aA5sNote three important things from this output:
username — the temporary user just created in PostgreSQL.password — the random password that only works for this user.lease_id — the unique identity used to track and revoke these credentials later.The same credentials are never issued twice: every bao read database/creds/my-role creates a new user with a new password. This is the essence of short-lived credentials — on-demand, unique, and automatically expiring.
Dynamic credentials live within the lease framework: a temporary contract between OpenBao and the consumer. When the lease ends, OpenBao automatically drops the user in the database. This means:
default_ttl (one hour in our example).max_ttl limit (24 hours).From the application side, a healthy pattern is to request credentials, use them briefly, and let them expire — or request new ones periodically. Never store dynamic credentials in a permanent configuration file, because that would eliminate their entire benefit.
Note
In MySQL, the expiration placeholder does not work the same way as in PostgreSQL. Use a template that matches your database plugin — the official plugin documentation provides example creation statements for each database.
In this episode 4, you understood the dynamic credentials concept that changes how you think about credentials, configured PostgreSQL and MySQL database connections in OpenBao, wrote database roles with creation_statements, default_ttl, and max_ttl, and retrieved short-lived credentials via bao read database/creds/my-role.
Key takeaways:
default_ttl sets the lifetime, max_ttl limits renewals.In the next episode, episode 5, we enter the world of the Transit Secrets Engine — Encryption-as-a-Service. OpenBao will handle the encryption and decryption of sensitive data such as national ID numbers, credit card numbers, or health data through its API, without ever storing that data in OpenBao. You will learn to create encryption keys, encrypt data with base64, and decrypt it again — all from a single bao command. See you in episode 5!