Written for: Engineering leads, DBAs and platform teams running PostgreSQL, MySQL, SQL Server, MongoDB or managed cloud databases
Database security audit checklist: from internet exposure to least privilege
Open ports, default accounts, encryption, least privilege, audit logs, backups, end-of-life versions and managed cloud settings, in the order we audit them.
Published · 10 min read
The database is usually where an intrusion turns into a breach. Whatever the way in, the damage is decided by who can reach the data, what they can do once connected, whether anyone would notice, and whether you can recover. A database security audit answers those four questions with evidence. This checklist follows the order we work in, from the network edge inwards, and ends with the findings we see most often.
Exposure and network reachability
Start from outside. A database that cannot be reached cannot be logged into, so exposure findings outrank almost everything else. Check from three vantage points: the internet, your office and VPN networks, and the inside of your own production network, where a single compromised container should not be able to reach every database.
- No database ports (5432, 3306, 1433, 27017, 6379, 9200 and their non-standard variants) reachable from the internet, confirmed by an external scan of your own address ranges rather than by reading the firewall configuration.
- No public admin consoles: phpMyAdmin, Adminer, Mongo Express, Kibana and cloud query editors restricted to administrators.
- Bind addresses set deliberately. MongoDB binds to localhost by default, so a configuration that listens on every interface was a choice; check PostgreSQL listen_addresses and MySQL bind-address the same way.
- Security groups and firewall rules that allow only the application subnets needing the database, with no 0.0.0.0/0 entries.
- Administrative access through a bastion host or an identity-aware proxy rather than directly from laptops.
- Replicas, analytics copies and old staging databases held to the same rules; the forgotten copy is often the exposed one.
Authentication, default accounts and secrets
Every engine ships with a powerful default account, and every estate accumulates shared ones. The audit question is simple: can each connection be traced to one person or one service, and is the method strong?
- Default superusers (postgres, root, sa and their equivalents) disabled, renamed or restricted to local break-glass use, with their passwords held in a vault.
- One account per application and per environment, and no people logging in with application credentials.
- PostgreSQL pg_hba.conf free of trust entries for network connections, with scram-sha-256 rather than md5 password authentication.
- MySQL accounts moved off mysql_native_password, which was deprecated in 8.0.34, is disabled by default in 8.4 and was removed in 9.0; accounts still using it cannot log in to 8.4 unless the plugin is explicitly re-enabled.
- MongoDB access control switched on; SCRAM is the default authentication mechanism.
- Redis, Elasticsearch and other services that teams think of as caches given authentication and network restrictions too.
- Human administrators authenticating through your identity provider, or the platform's IAM database authentication, with multi-factor authentication.
Secrets in connection strings
Database passwords leak from wherever connection strings are written down: source repositories and their history, CI logs and variables, container image layers, infrastructure state files, environment files copied into front-end builds, and crash reports. Check all of them, then move to a secrets manager with rotation or, better, to short-lived credentials issued per session.
Backend-as-a-service platforms need particular care because the database is reachable from the browser by design. Supabase's documentation says to enable row level security on every table in an exposed schema, warns that a table in an exposed schema without it is readable and writable by any role with a grant on it, and says that secret keys, which bypass row level security, must never be used in the browser.
Encryption and least privilege
Encryption
- TLS required for every client connection, not merely available, and clients verifying the server certificate (for PostgreSQL clients, sslmode=verify-full).
- Encryption at rest through the engine, the storage layer or the cloud provider's key service, with key administration separated from database administration.
- Backups and exports encrypted with keys held outside the backup system.
- Field-level encryption for the most sensitive columns where the platform supports it, such as SQL Server Always Encrypted or MongoDB's Queryable Encryption and client-side field level encryption.
Least privilege
The most consequential database finding is usually not a missing patch but an application connecting as a superuser or database owner, so that one injection flaw exposes everything. Israel's regulations put the principle in law: Regulation 8 allows access only to the extent required for the role, and requires an up-to-date list of roles, their permissions and the people holding them. A sound model has four kinds of account:
- 1
A migration role
Owns the schema and runs migrations from the deployment pipeline. Nothing else uses it, and it is not available to the running application.
- 2
A runtime role
The application's account, with only the reads and writes it needs on the tables it uses: no DDL, no ownership, no access to other schemas or databases.
- 3
Read-only roles
For analytics, reporting and support, scoped to the tables and columns each group needs, with sensitive columns masked or excluded.
- 4
Named administrators
Individual accounts for the people who administer the database, used only for administration, with every session attributable to one person.
- In PostgreSQL, CREATE on the public schema revoked from PUBLIC. Version 15 changed this default for new databases, but upgraded clusters and restored dumps keep the old, permissive setting.
- No grants to PUBLIC that nobody can explain, and SECURITY DEFINER functions reviewed and given a fixed search_path.
- Access for leavers and former suppliers removed promptly; Israel's Regulation 9 requires revoking a departing user's permissions immediately and, as far as possible, changing passwords they could have known.
- Row level security, or an equivalent tenant filter enforced in the database, on multi-tenant tables.
- A quarterly review that compares the privileges granted to each role with the privileges it actually used.
Auditing, logging and detection
If someone exported the customer table last Tuesday, could you tell? Default logging usually records connections and errors, not reads, so auditing access to sensitive data takes deliberate configuration: the pgAudit extension for PostgreSQL, SQL Server Audit, an audit plugin for MySQL or MariaDB, or the auditing facility in MongoDB Enterprise, which can record user operations and connection events.
- Logins and failed logins, privilege and role changes, schema changes and access to sensitive tables recorded.
- Logs shipped off the database host to storage that database administrators cannot edit or delete.
- Alerts on bulk reads and exports, new privileged accounts, bursts of failed logins and connections from new sources.
- A named person who reviews the alerts, and a record that they did.
Backups, patching and benchmarks
Backups
- Backups encrypted and stored under a separate account or separate credentials, so that a compromised production administrator cannot delete them.
- At least one immutable or offline copy.
- Point-in-time recovery configured, with a retention window longer than an intrusion might plausibly go unnoticed.
- A restore tested and timed on a schedule, with the result recorded.
- No stray dumps on shared drives, laptops or storage buckets.
Patching and supported versions
Unsupported versions stop receiving security fixes, and several mainstream engines have crossed that line recently. Israel's Regulation 13 also bars the use of systems whose manufacturer no longer supports their security aspects, unless an appropriate security solution is in place.
| Engine | Lifecycle position | What to do |
|---|---|---|
| PostgreSQL | Each major version is supported for five years. Version 13 reached end of life on 13 November 2025, and version 14 follows on 12 November 2026. | Plan the major upgrade, and keep up with minor releases, which ship at least every three months. |
| MySQL 8.0 | Reached end of life in April 2026; Oracle points users to 8.4 LTS or 9.7 LTS. | Upgrade, checking authentication plugins first. |
| SQL Server 2016 | Extended support ended in July 2026, with Extended Security Updates offered until July 2029. | Upgrade, or enrol in Extended Security Updates and record the exception. |
| Managed cloud engines | The provider sets the version calendar and retires old major versions on its own schedule. | Track the provider's deprecation notices and schedule upgrades before they are forced. |
CIS Benchmarks
The Center for Internet Security publishes consensus-based secure configuration benchmarks for PostgreSQL, MySQL, MariaDB, Microsoft SQL Server, Oracle Database, MongoDB, Apache Cassandra and others. Use the relevant benchmark as your baseline, record each deviation with its reason and owner, and map audit findings to benchmark items so that progress can be measured from one audit to the next.
Managed cloud databases and data classification
Managed is not the same as configured
With a managed database the provider runs the hardware and the operating system and supplies engine patches. Network exposure, authentication, privileges, key choices, backup retention and sharing, and logging remain yours. Audit the settings the console makes easy to change:
- Public accessibility switched off, with private endpoints or service endpoints in place of broad network rules.
- On Azure SQL, the 'Allow Azure services and resources to access this server' setting reviewed: Microsoft warns that it admits connections from all Azure services, including those in other customers' subscriptions, and suggests private endpoints or virtual network service endpoints instead.
- Snapshots and backups not shared publicly or with accounts you do not control.
- Cloud IAM roles that can modify, restore, export or delete databases kept to a minimum and monitored, because they work around database permissions entirely.
- Parameter settings that enforce TLS and auditing, deletion protection switched on, and audit logs exported to your logging platform.
Data classification
An audit is faster, and its findings easier to rank, when you know which tables hold personal data, payment data, health data, credentials and secrets. Classification also decides your obligations. Israel's regulations place each database in one of four tiers: managed by an individual, or at a basic, medium or high security level; high-level databases need a risk assessment and penetration tests at least every 18 months (Regulation 5), and medium and high-level databases need an audit at least once every 24 months by an auditor who is not the database's own security officer (Regulation 16). Our compliance overview covers the other regimes.
What we see most often
- Search cluster or cache open to the internet: an Elasticsearch, OpenSearch or Redis instance on a public address without authentication, holding a copy of customer data that was only ever meant to be an index or a cache.
- Application connects as the superuser: production runs on the database owner or superuser account, so one injection flaw becomes full read and write access and, on some engines, command execution on the host.
- Shared logins and no audit trail: engineers and support staff share one read-write account with audit logging off, so nobody can say who exported a table or when.
- Unmasked production copies in staging: full production data restored into staging or analytics, where access control, monitoring and patching are all weaker.
- Password still in the repository history: a connection string committed and later deleted survives in the history and every clone, and the password was never changed.
- TLS offered but not required: the server also accepts plaintext connections, and clients connect without verifying its certificate.
- Snapshots shared more widely than the database: the live database is locked down, but whoever can restore a shared snapshot has the whole data set.
- Stale accounts and grants: logins for leavers, retired services and one-off migrations, each one a working account that no current person or system owns.
Our database security audit follows this order of work, with evidence for each finding and a fix order your team can act on. Where the database runs in AWS, Azure or Google Cloud, a cloud configuration review complements it by tracing the identity and network paths that lead to the database.
Sources
- Protection of Privacy Regulations (Data Security) 5777-2017, unofficial English translation (opens in a new tab) · Privacy Protection Authority (gov.il)
- Versioning Policy (opens in a new tab) · PostgreSQL Global Development Group
- PostgreSQL 15 Release Notes (opens in a new tab) · PostgreSQL Global Development Group
- MySQL end-of-life notice (opens in a new tab) · Oracle (mysql.com)
- MySQL 8.4 Reference Manual: Native Pluggable Authentication (opens in a new tab) · Oracle (dev.mysql.com)
- SQL Server 2016 lifecycle (opens in a new tab) · Microsoft Learn
- Security Checklist for Self-Managed Deployments (opens in a new tab) · MongoDB Documentation
- IP Binding (opens in a new tab) · MongoDB Documentation
- Row Level Security (opens in a new tab) · Supabase Docs
- IP firewall rules: Azure SQL Database (opens in a new tab) · Microsoft Learn
- CIS Benchmarks (opens in a new tab) · Center for Internet Security