Most database breaches use a valid credential: a connection string in a config file, a shared application password nobody rotates, or a default superuser that was never disabled. Database credentials are some of the most powerful non-human identities in any estate, because whoever holds the application's password can read everything the application can. This guide goes deeper than the Database Security Guide on one part of the problem: database credentials, database service accounts, privilege management and access control. It covers where static credentials live and leak, how to move to dynamic database credentials and IAM database authentication on AWS, Google Cloud and Azure, rotation that does not cause outages, least privilege role design, and privileged, just-in-time and break-glass access. It is written for platform engineers, DBAs, application security and identity teams.
Key takeaways
- Every database login is an identity with an owner. One account per application and environment, never a shared login, and never the built-in sa, root, postgres or SYS account for applications.
- The best database password is one that does not exist. IAM database authentication, managed identities and dynamic database credentials remove long-lived secrets from connection strings altogether.
- Rotation needs a design, not a schedule. Alternating users or dual passwords let you rotate without dropping connections; single-user rotation needs retry logic.
- Least privilege lives in roles. Group privileges in non-login roles, keep schema ownership away from the runtime account and treat file and program execution roles as superuser equivalents.
- Humans get just-in-time access, not shared admin passwords. Named, time-bound, logged access through the identity provider or an access proxy, with a sealed break-glass account for when that fails.
Database credential types and their risks
Start with an inventory. Most estates have the same seven kinds of database credential, and each needs a different target state.
| Credential | Typical problem | Target state |
|---|---|---|
| Application service account (runtime) | Static password in a connection string, shared across environments, over-privileged | One per application and environment; IAM or dynamic credentials, or a vaulted and rotated password; DML only |
| Migration or deployment account | Same account as runtime, so the application can ALTER and DROP | Separate account used only by the release pipeline, ideally issued per run |
| Built-in superuser (sa, root, postgres, SYS) | Enabled, known name, weak or shared password, used by applications | Disabled or sealed as break-glass; never used by applications |
| DBA and engineer accounts | Shared admin login, standing access | Named accounts through the identity provider, just-in-time elevation, MFA |
| Reporting, BI and analytics accounts | One shared read account in many tools and notebooks | Per-tool service accounts with read-only roles and row or column limits |
| Vendor, monitoring and backup accounts | Default or hard-coded credentials, broad rights | Changed at install, scoped to the function, owner recorded |
| Break-glass account | Password known to several people, never tested | Vaulted, split or sealed, alerted on use, tested on a schedule |
Treat the runtime account as a privileged non-human identity with a named owner, a purpose and a review date. See the Service Account Security Guide.
Connection strings and static database credentials
A database connection string usually carries the host, database, user name and password together, which makes it a complete credential wherever it is copied. OWASP's Database Security Cheat Sheet is direct: "Database credentials should never be stored in the application source code", and configuration files holding them should sit outside the web root and out of source control.
- Where they leak: committed config files, container images and Helm values, CI/CD variables printed in logs, notebooks, BI tool data sources, wiki pages and support tickets. OWASP's secrets detection guidance lists both "Application configuration files" and "Connection strings" as places to scan.
- Environment variables are not a vault: OWASP warns they "are generally accessible to all processes and may be included in logs or system dumps" and recommends them only when other methods are not possible. Prefer the platform's secret store, a mounted secret file or, better, no secret at all.
- Shared database credentials: one password used by several applications or people destroys accountability and makes rotation a coordinated outage, so nobody rotates it. OWASP's rule is that each account is "Used by a single application or service."
- Weak and default database credentials: default and vendor-supplied accounts are the first thing attackers try. The JADEPUFFER agentic ransomware case used harvested and default credentials to destroy a production database, and the SAP SQL Anywhere Monitor hard-coded credentials flaw scored a maximum 10.0.
- Leaked database credentials: when one leaks, rotate it at the database, then check database logs for use from unexpected hosts. OWASP notes that "Restarting the application does not itself revoke stolen credentials." See the Leaked Credential Response Playbook.
Authentication options: from passwords to identity
The strongest pattern is to authenticate the workload with the platform's identity and let the database accept a short-lived token, so no database password is stored anywhere. Where that is not available, issue credentials dynamically; only then fall back to a vaulted, rotated static password.
| Option | How the credential is issued | Lifetime | Watch out for |
|---|---|---|---|
| AWS RDS IAM authentication (MariaDB, MySQL, PostgreSQL) | Application signs a token request with its IAM role; token used as the password over TLS | Token valid 15 minutes; session continues after | CloudTrail and CloudWatch do not log token generation; PostgreSQL users granted rds_iam can no longer use a password; plan memory headroom |
| Google Cloud SQL IAM database authentication | Principal with the cloudsql.instances.login permission presents an OAuth 2.0 access token; automatic mode through the Cloud SQL Auth Proxy or connectors | Access token valid one hour | Enable the cloudsql.iam_authentication flag; database privileges still come from GRANT; group membership changes take time to revoke |
| Microsoft Entra authentication for Azure SQL | Managed identity or Entra user token; contained users created FROM EXTERNAL PROVIDER | Token based | A single Entra admin per server; turn on Microsoft Entra-only authentication to disable SA and SQL logins; service principal secrets are "not recommended" |
| Windows or Kerberos authentication (SQL Server, on premises) | Service runs as a domain account, ideally a gMSA | Kerberos tickets | Microsoft calls Windows authentication "much more secure than SQL Server Authentication"; keep SPNs and delegation tidy |
| Dynamic database credentials | A secrets engine creates a database user on request and drops it when the lease ends | Minutes to hours | Connection pools, object ownership and engine user limits |
| Vaulted, rotated static password | Secret store holds the password and rotates it on a schedule | Days to months | Rotation strategy and every copy outside the vault |
- IAM database authentication still needs database roles: the cloud identity proves who is connecting; what that user can do inside the database is still governed by grants, so least privilege applies unchanged.
- Use a database access proxy where it helps: Amazon RDS Proxy can require IAM authentication from clients while it holds the database secrets (up to 200 per proxy) or uses IAM to the database; the Cloud SQL Auth Proxy handles IAM tokens for long-running applications. A proxy moves the credential problem to one controlled place.
- Federate from outside the cloud: workloads in CI or another cloud can obtain cloud credentials through workload identity federation and then use IAM database authentication, with no stored secret. See the Workload Identity Federation Guide.
Dynamic database credentials and secrets engines
A database secrets engine is a secrets manager component that holds one privileged connection to the database and creates short-lived users on request from a role template (for example "create a login role with SELECT on schema app, valid for one hour"). The application authenticates to the secrets manager with its workload identity, receives a unique user name and password with a lease, and the engine revokes the user when the lease expires or is revoked early.
- Why it helps: OWASP: "Dynamic secrets should be used where possible to reduce the surface area of credential reuse." Every instance gets its own credential, so a leak identifies its source and expires on its own, and use from a different IP address stands out.
- Protect the engine's own account: the connection the engine uses can create users, so it is the new crown jewel. Rotate it after setup so no human knows it, and grant it only the rights needed to create and drop the roles it manages.
- Design for object ownership: dynamic users should be members of a pre-created NOLOGIN group role and never own tables, or dropping them fails or orphans objects.
- Size leases to the workload: short leases suit batch jobs and humans; long-running services need renewal logic and connection pools that reconnect cleanly.
- Revocation must reach the database: OWASP: "stopping the consumer alone does not revoke the secret." Test that revocation actually terminates sessions or blocks new logins.
Product choice and secret store architecture are covered in the Secrets Management Guide.
Database credential rotation without outages
Static database password rotation fails when applications cache the old password, so the change breaks production and teams stop rotating. Choose a strategy that fits the engine and the application.
- Single user rotation: AWS Secrets Manager calls it "the simplest rotation strategy, and it is appropriate for most use cases"; open connections are not dropped, but there is a short window where new connections can fail, so applications need retry logic.
- Alternating users: the rotation function clones the user and alternates which one it changes, so "both user and user_clone credentials are valid" after rotation. It suits high availability, but needs a superuser secret to create the clone, and permission changes must be applied to both users.
- MySQL dual passwords: set a new primary password with RETAIN CURRENT PASSWORD, move applications to it, then DISCARD OLD PASSWORD once all servers have it; MySQL describes this as allowing changes "without downtime".
- PostgreSQL VALID UNTIL is not rotation: it expires the password only, and the PostgreSQL manual notes it "is not enforced when logging in using a non-password-based authentication method."
- Interval: rotate automatically on a schedule the application tolerates, and immediately on staff changes, suspected leak or vendor access ending. Measure rotation success, not just configuration. See Guide to NHI Rotation Challenges.
Least privilege database access and privilege management
Database access control and privilege management work best with three layers: non-login roles that hold privileges, login accounts that are members of them, and ownership kept separate from use. PostgreSQL's manual describes the model: roles without LOGIN "are useful for managing database privileges, but are not users in the usual sense of the word."
| Privilege or role | Why it is dangerous | Guidance |
|---|---|---|
| PostgreSQL SUPERUSER, MySQL root, SQL Server sysadmin, Oracle SYS | Bypasses all permission checks; PostgreSQL calls superuser status "dangerous" | No application or routine human use; break-glass only |
| pg_read_server_files, pg_write_server_files, pg_execute_server_program | Bypass database permission checks for files and programs and "could be used to gain superuser-level access" | Treat as superuser; grant only to named admin roles |
| pg_read_all_data, pg_write_all_data | Read or write every table in the database | Reserve for backup or audit tools; never the default reporting role |
| BYPASSRLS and table ownership | Owners and BYPASSRLS roles skip row-level security | Runtime accounts never own objects and never hold BYPASSRLS |
| CREATEROLE, GRANT OPTION, ALTER ANY LOGIN | Can create or empower other accounts | Only the provisioning or secrets engine account |
| DDL rights (CREATE, ALTER, DROP) | Application or AI agent can destroy schema | Migration account only, used during releases |
- Grant per schema and table: runtime accounts need SELECT, INSERT, UPDATE and DELETE on named objects, not database-wide rights. OWASP: "Do not use the built-in root, sa or SYS accounts" and "Do not grant the account administrative rights over the database instance."
- Scope by host and connections: MySQL accounts are defined per host, so avoid '%'; PostgreSQL CONNECTION LIMIT caps a role's sessions (it is never enforced for superusers).
- Lock out guessing: MySQL FAILED_LOGIN_ATTEMPTS with PASSWORD_LOCK_TIME locks an account after consecutive failures; for SQL Server logins enable password policy enforcement.
- Remember agents and automation: a CI token or AI coding agent with production database rights is a database user too. The PocketOS database deletion happened when an agent used an over-privileged platform token to wipe production.
Privileged database access: sa, JIT and break-glass
- SQL Server sa account: Microsoft: "Because the sa account is well known and often targeted by malicious users, don't enable the sa account unless your application requires it. Never set a blank or weak password for the sa account." With Windows Authentication mode, setup creates sa disabled. On Azure SQL, Microsoft Entra-only authentication disables SA and every SQL login.
- Named privileged access: DBAs connect as themselves through the identity provider (Entra, IAM, Kerberos) with MFA, so every privileged statement maps to a person. See the Privileged Access Management Guide.
- Database just-in-time access: grant elevated roles for a ticketed window and remove them automatically: time-boxed membership of an identity provider group mapped to a database role, a dynamic credential with a one-hour lease, or an access proxy that brokers and records the session. JIT database access removes standing admin rights without slowing incident work. See the JIT Access Guide.
- Session recording: for production data changes, record privileged sessions through a proxy or bastion. See the Privileged Session Management Guide.
- Database break glass account: keep one local superuser for when the identity provider or proxy is down. Store it in a secrets manager with a secondary copy (OWASP recommends backing up break-glass credentials "in a secondary secrets management system"), alert on every use, rotate after use and test it quarterly. See the Break-Glass Account Guide.
Database user provisioning and access governance
- Provision from groups: database access governance starts with joiners and leavers flowing from the identity provider. Cloud SQL IAM group authentication and Entra groups mapped to contained database users do this without DBA tickets. Remember that removal can lag: Google notes it "can take some time to revoke" inherited group privileges.
- Reconcile local accounts: compare database logins against the identity provider and the service account inventory monthly; disable accounts with no owner or no login in 90 days. See the Joiner-Mover-Leaver Guide.
- Review entitlements, not just accounts: include role memberships, direct grants and owners in access reviews, with the application owner certifying service accounts. See the Access Reviews Guide.
Detection and measurement
Database audit logs should go to central logging off the database host. Alert on:
- Logins by sa, root, postgres or the break-glass account.
- Application service accounts connecting from hosts outside the application tier, or interactively from a client tool.
- Failed login bursts and account locks.
- CREATE USER, ALTER ROLE, GRANT and changes to authentication settings outside change windows.
- IAM token use you cannot see: because CloudTrail does not log RDS IAM token generation, rely on database-side connection logs for those users.
Metrics that show it is working:
- Share of application database connections using IAM, managed identity or dynamic credentials (rising).
- Static database passwords older than the rotation policy (target: zero).
- Database credentials found in repositories, images or tickets per month, and mean time to rotate them.
- Accounts holding superuser-equivalent roles, by name (target: DBAs via JIT plus break-glass only).
- Logins with no identified owner (target: zero).
Implementation roadmap
- Inventory: list every database login, its type, owner, privileges, authentication method and last use, and find where each credential is stored.
- Remove the worst first: disable or seal sa, root and postgres for routine use, change default and vendor passwords, and split shared credentials into one per application.
- Vault and rotate: move remaining static credentials into the secret store, pilot rotation on one non-production application with alternating users or dual passwords, then extend. Roll back by restoring the previous secret version.
- Move to identity: switch cloud databases to IAM or Entra authentication and on-premises SQL Server to Windows authentication with gMSAs, one application at a time, keeping the password login disabled but present until the new path is proven.
- Introduce dynamic credentials for batch jobs and human access, then for services that handle lease renewal.
- Fix privileges: create NOLOGIN roles per function, separate migration from runtime accounts, remove ownership and superuser-equivalent roles.
- Govern: JIT for DBAs, quarterly access reviews and alerting as above.
Decision guidance
- IAM authentication or dynamic credentials: on AWS, Google Cloud or Azure managed databases, prefer the native IAM or Entra method: no secret, no engine to run. Use dynamic credentials for self-managed engines, multi-cloud estates or where you need per-session users.
- Single user or alternating users rotation: single user for most applications with retry logic and for ad hoc users; alternating users for high-availability services that cannot tolerate a failed connection.
- Small and large organisations: a small team gets most of the value from one account per application, a managed secret store with rotation, IAM authentication on managed databases and disabling sa. Large estates add a secrets engine, an access proxy for human access, automated reconciliation and entitlement reviews.
Framework mapping
| Control area | NIST SP 800-53 Rev. 5 | CIS Controls v8.1 | ISO/IEC 27001:2022 |
|---|---|---|---|
| Account inventory, owners and reviews | AC-2 | 5.1, 5.5 | A.5.16, A.5.18 |
| Least privilege and privileged accounts | AC-6, AC-6(5) | 5.4, 6.8 | A.8.2 |
| Credential storage, strength and rotation | IA-5 | 5.2 | A.5.17 |
| Centralised authentication and MFA for admins | IA-2 | 6.5, 6.7 | A.8.5 |
| Logging of database access | AU-2, AU-6 | 8.2, 8.5 | A.8.15 |
In MITRE ATT&CK (v20), database credential misuse is T1078 Valid Accounts (T1078.001 Default Accounts for vendor and built-in logins), and harvesting connection strings from configuration falls under T1552.001 Unsecured Credentials: Credentials In Files.
Common failure patterns
- One credential, many systems: the GoDaddy Managed WordPress breach shows how one compromised password exposed sFTP and database credentials together.
- Rotation configured, never tested: the first rotation breaks a cached connection pool, the job is disabled and the password stays the same for years.
- IAM authentication with admin grants: passwords removed, but the IAM-mapped user still owns the schema or holds superuser.
- Exposed data stores holding secrets: the Moltbook database exposure leaked 1.5 million AI agent API keys from an open database.
- Break-glass that nobody can open: the emergency password was rotated by automation and never stored where responders can reach it.
Practitioner checklist
- Inventory every database login with type, owner, privileges, authentication method and last use.
- Give each application and environment its own account; remove shared credentials.
- Disable sa, root and postgres for routine use and keep one tested break-glass account.
- Remove credentials from source, images and tickets; scan for connection strings.
- Use IAM, Entra or Windows authentication where the platform supports it; otherwise dynamic credentials or vaulted, rotated passwords.
- Choose a rotation strategy per application and test it before enabling the schedule.
- Separate migration and runtime accounts; runtime accounts get DML on named objects only.
- Treat file and program execution roles and BYPASSRLS as superuser equivalents.
- Give DBAs named, just-in-time access with MFA and session logging.
- Alert on superuser logins and service accounts used from unexpected hosts.
Standards and references
- OWASP: Database Security Cheat Sheet
- OWASP: Secrets Management Cheat Sheet
- NIST: SP 800-53 Rev. 5, Security and Privacy Controls for Information Systems and Organizations
- Microsoft Learn: Choose an authentication mode (SQL Server)
- Microsoft Learn: Microsoft Entra authentication for Azure SQL
- AWS: IAM database authentication for Amazon RDS
- Google Cloud: Cloud SQL IAM database authentication
- PostgreSQL: Predefined roles
Related NHI Mgmt Group resources: Database Security Guide · Secrets Management Guide · Service Account Security Guide · JIT Access Guide