Stopping the Password Rotation Cycle with Vault Dynamic Database Secrets
Stop managing static database passwords. Learn how to use HashiCorp Vault's Database secrets engine to generate on-demand, short-lived credentials for PostgreSQL.
08 Aug 2026, 06:34 UTC

The Burden of Static Database Credentials
Most engineering teams handle database security by creating a single service account with a static password. To meet compliance requirements, they then build complex rotation pipelines: a script that updates the password in the database and then pushes that new secret to a configuration provider or environment variable. This process is fragile. If the update fails halfway through, the application loses connectivity; if the secret leaks, it remains valid until the next rotation cycle.
The alternative is to move from static secrets to dynamic credentials. Instead of sharing one password, the application requests a unique, short-lived set of credentials from HashiCorp Vault on demand. Vault creates a temporary user in the database, assigns it the necessary permissions, and automatically deletes that user when the lease expires.
How the Database Secrets Engine Works
The Database secrets engine functions as a privileged proxy. You provide Vault with a "root" account—one with enough permissions to create and drop other users. When an application requests credentials for a specific role, Vault executes a pre-defined SQL statement to generate a new user.
The Lease Lifecycle
Every dynamic credential is bound to a lease. A lease is a time-limited agreement that defines how long the credential remains valid. This lifecycle consists of three main stages:
- Creation: Vault generates a unique username and password and returns them to the client.
- Renewal: The client can extend the lease periodically, provided it hasn't reached the
max_ttl(Maximum Time To Live). - Revocation: Once the lease expires or is manually revoked, Vault connects to the database and executes a
DROP USERor similar command to remove the account.
Practical Implementation: PostgreSQL Example
To implement this, you must first enable the engine and configure the connection. This example assumes you are running the Vault CLI with administrative permissions on a cluster running Vault 1.12+.
1. Configure the Connection
Run this command to tell Vault how to connect to your PostgreSQL instance. Replace the placeholders with your actual database details.
# Run as Vault Admin
vault write database/config/my-postgres \
plugin_name=postgresql-database-plugin \
allowed_roles="read-only-role" \
connection_url="postgresql://{{username}}:{{password}}@postgres.example.com:5432/mydb?sslmode=disable" \
username="vault_admin" \
password="admin_password"2. Define the Role
The role defines the SQL statements used to create and revoke the temporary users. This ensures the principle of least privilege.
# Run as Vault Admin
vault write database/roles/read-only-role \
db_name=my-postgres \
creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; \
GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \
default_ttl="1h" \
max_ttl="24h"3. Requesting Credentials
The application (or a developer) can now request credentials. Each request generates a distinct user.
# Run as Application Identity
vault read database/creds/read-only-roleVerification: If you run the read command twice, you will receive two different usernames. You can verify these users exist by logging into PostgreSQL and running \du. Running vault lease revoke [lease_id] will immediately remove the user from the database.
Operational Trade-offs and Limitations
While dynamic secrets eliminate the need for rotation pipelines, they introduce new architectural dependencies.
The Availability Dependency
Vault becomes a hard dependency for database access. If Vault is down and your application needs to renew a lease or request new credentials, the app will fail to connect. To mitigate this, use Vault Agent for auto-auth and credential caching, allowing the app to rely on a locally cached lease during brief outages.
Database Resource Pressure
Frequent requests for short-lived credentials can lead to "user proliferation." In some databases, creating and dropping thousands of users per hour can bloat system catalogs or exhaust connection pools. To prevent this, align your default_ttl with your application's recycling or deployment patterns rather than setting it to an aggressively short window (e.g., use 1 hour instead of 5 minutes).
Orphaned Users
Revocation relies on Vault's ability to reach the database. If the network connection between Vault and the database is severed for a period longer than the lease duration, Vault may fail to execute the DROP USER command, leaving orphaned users in your database. A periodic cleanup script on the database side is a recommended safety measure.
Closing Action
To start transitioning, identify your most critical service account. Instead of rotating its password, create a Vault role that mirrors its permissions. Deploy a test instance of your application using the database/creds/ endpoint and monitor the database's system catalogs to ensure user creation and deletion are behaving as expected before removing the static account.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.