Credential rotation
What actually rotates, when the old password stops working, and which parts of your stack update themselves.
What rotates
Rotation replaces exactly one thing: the database password for the project's role. The host, ports, database name, and role name all stay the same — only the password segment of your connection URLs changes. API keys, webhook secrets, and integration tokens have their own rotation surfaces and are untouched.
The new password is generated server-side (a 24-byte random secret), stored AES-GCM encrypted in the control plane, and applied on the database host with an ALTER ROLE. It is never chosen by, or shown to, anyone before it lands in your connection details.
Triggering a rotation
From the dashboard (the project's Connections tab or Settings → Rotate Credentials) or the API:
curl -X POST https://capydb.dev/api/capydb/v1/projects/$PROJECT_ID/credentials/rotate \
-H "Authorization: Bearer $CAPYDB_API_KEY"There is no dedicated CLI command for rotation today; capydb connection-string will hand you the fresh URLs once the rotation completes.
Rotation is asynchronous: the response is a job, the project moves to a rotating_credentials state, and flips back to ready when the job completes. Poll GET /v1/jobs/{id} or listen for the events below. The job retries up to 3 times on transient failure; if it fails terminally, the old password remains valid and the project returns to ready.
Invalidation timing
- Until the job completes, the old password keeps working. Rotation is requested, not instant.
- Once the job completes, new connection attempts with the old password fail — on both the direct and pooled endpoints simultaneously, since both authenticate against the same database role.
- Already-open connections are not terminated. A session established before the rotation keeps working until it disconnects on its own. If "no session may outlive the old credential" is a hard requirement (a leaked URL, an offboarding), rotate and then restart your app processes so every pool reconnects with the new password.
What updates itself
- Connected Vercel and Netlify integrations re-push
DATABASE_URL/DATABASE_URL_UNPOOLEDautomatically after the rotation job succeeds (the sync itself retries up to 5 times). Note that already-running deployments baked the old env vars at build/boot time — trigger a redeploy to pick up the new URLs. - A
credentials.rotatedwebhook event fires (plus the genericjob.completed), so your own automation can react. - The audit trail records
project.credentials_rotatedwith the job ID and role name.
Everything else — CI secrets, local .env files, password managers, that one cron job on a forgotten VM — holds the old URL until you update it.
Runbook
- Pause anything that auto-restarts database workers mid-deploy, if reconnect storms matter to you.
- Trigger the rotation (dashboard or
POST /v1/projects/{id}/credentials/rotate). - Wait for completion: poll the job, or act on the
credentials.rotatedwebhook. - Fetch the new URLs: dashboard Connections tab,
GET /v1/projects/{id}/connections, orcapydb connection-string. - Update every consumer that is not a connected Vercel/Netlify integration: CI secrets, other hosts, local env files.
- Redeploy / restart app processes — both to pick up pushed env vars and to drop any sessions still authenticated with the old password.
- Confirm: new connections succeed, and the audit trail shows the rotation.
When to rotate
- A connection URL leaked — committed to a repo, pasted in a chat, logged somewhere.
- Someone with database access left the team.
- Routinely, if your security policy wants credential turnover; rotation is cheap and does not touch data.