What this check reads
The check queries SELECT user,host FROM mysql.user WHERE Super_priv='Y', excluding the same fixed system list as the FILE check: root, mysql.session, mysql.sys, mysql.infoschema, mariadb.sys, mysql, debian-sys-maint and percona.telemetry. It reads that one column and nothing else, so the MySQL 8 dynamic privileges held in mysql.global_grants never reach the result. One surviving row is the threshold: any account left after the exclusions is a WARN listing each user@host pair, and an empty result passes.
When it applies
Runs only when MySQL/MariaDB is detected and reachable as root over the socket (MYOK=1); otherwise SKIP. It tests exactly one column - Super_priv in mysql.user - excluding the same fixed system account list as the FILE check. MySQL 8 dynamic privileges (SYSTEM_VARIABLES_ADMIN, CONNECTION_ADMIN, SET_USER_ID, BACKUP_ADMIN, …) live in mysql.global_grants and are not examined, so an account with near-superuser dynamic privileges but no SUPER passes this check.
What each result means
| Result | When | What it means |
|---|---|---|
| WARN | Non-system accounts hold SUPER | An account outside the expected system set holds administrative rights over the whole server, not just its own schema. |
| PASS | None | No unexpected account holds SUPER, though dynamic privileges of comparable power are outside what this check sees. |
| SKIP | Not accessible | Nothing was verified. MySQL could not be queried as root, so no account has been cleared of administrative rights. |
Why it matters
SUPER (deprecated in MySQL 8.0 in favour of dynamic privileges, still present) allows changing global variables, killing any session, bypassing read_only, setting definers, and more. Application accounts need only DML on their schema. OWASP: no admin rights for application accounts; CIS MySQL "Ensure 'SUPER' is not granted to non-administrative users".
Why it fails, and when it is wrong
GRANT ALL ON *.*to an app user, or a migration tool run with an admin account that was later reused by the app.- Replication, monitoring (
pmm,zabbix) and backup accounts sometimes hold SUPER when they only needREPLICATION CLIENT,PROCESS,BACKUP_ADMINetc. - MySQL 8 dynamic privileges (
SYSTEM_VARIABLES_ADMIN,CONNECTION_ADMIN,SET_USER_ID) are not checked; an account with those but without SUPER passes.
How to fix it
REVOKE SUPER ON *.* FROM 'app'@'10.0.0.5';
GRANT SELECT,INSERT,UPDATE,DELETE ON appdb.* TO 'app'@'10.0.0.5';
-- inspect dynamic privileges too:
SELECT * FROM mysql.global_grants WHERE user NOT IN ('root','mysql.session','mysql.sys','mysql.infoschema');Verify the fix
sudo mysql -N -e "SELECT CONCAT(user,'@',host) FROM mysql.user WHERE Super_priv='Y'"
# expected: only system accounts
# The blind spot - dynamic privileges the check never looks at:
sudo mysql -e "SELECT user, host, priv FROM mysql.global_grants
WHERE user NOT IN ('root','mysql.session','mysql.sys','mysql.infoschema')"
# expected: nothing broad (SYSTEM_VARIABLES_ADMIN, SET_USER_ID, CONNECTION_ADMIN)
sudo mysql -e "SHOW GRANTS FOR 'app'@'10.0.0.5'"
# expected: only DML on the application schemaDebugging
MYOK=0; see the Authentication debugging notes.
These often hold SUPER when they need far less: REPLICATION CLIENT, REPLICATION SLAVE, PROCESS, or BACKUP_ADMIN. Grant the specific privilege and revoke SUPER; the finding then clears legitimately.
The known blind spot. Run the mysql.global_grants query above; dynamic privileges such as SYSTEM_VARIABLES_ADMIN are close to SUPER in power and this check cannot see them.
SUPER is deprecated there; the server may tell you to use dynamic privileges instead. Revoke it anyway if the column says Y, then grant the narrow dynamic privilege the account actually needs.
It was relying on something specific: bypassing read_only, setting a definer, or changing a global variable at runtime. Find out which from the error, then grant just that dynamic privilege rather than restoring SUPER.
Sources
- MySQL 8.4: Privileges Provided (SUPER and dynamic privileges)
- MySQL 8.4: Static vs Dynamic privileges / mysql.global_grants
- MySQL 8.4: GRANT
- MariaDB KB: GRANT (SUPER)
- OWASP Database Security Cheat Sheet (Permissions)
How the script reads this
Next
Re-run the Least-Privilege Permissions audit after applying the fix and confirm this check moves to PASS. CtrlOps runs all 6 checks over your existing SSH connection and scores the result, so the change is visible without reading another config file.
All 6 Least-Privilege Permissions fixes