Every app gets its own credentials
This is a hard rule in the lab: no application ever connects as the database admin. Each app gets its own database, its own user, and its own password, scoped to just that database.
# for an app 'foo', on PostgreSQL:
CREATE DATABASE foo;
CREATE USER foo WITH PASSWORD '<REDACTED>';
GRANT ALL PRIVILEGES ON DATABASE foo TO foo;
# the same idea on MySQL / MariaDB (user scoped to the private subnet):
CREATE DATABASE foo;
CREATE USER 'foo'@'10.100.100.%' IDENTIFIED BY '<REDACTED>';
GRANT ALL PRIVILEGES ON foo.* TO 'foo'@'10.100.100.%';
And the admin accounts — postgres, and root on both MariaDB and MySQL — are local-only, reachable on the box itself, never over the network. Postgres enforces this in pg_hba.conf (the subnet is allowed for normal users, the superuser is explicitly rejected from the network); MariaDB and MySQL simply have no remote root user at all. The databases listen on the network for app users, and the firewall limits even that to the private subnet.
So a compromised or buggy app can, at worst, hurt its own database — never the whole server, never another app's data. Kong, for example, connects as a dedicated kong user to a kong database and could not touch anything else if it tried.
Why we use this: least privilege isn't bureaucracy, it's blast-radius control. The day an app is compromised, "it had its own scoped user" is the difference between losing one app's data and losing the database server. It costs three SQL statements per app. There's no excuse not to.