Chapter 11 · Users, Roles, Authentication, Authorization, and Least Privilege
Privileges, Roles, DEFAULT ROLE, Dynamic Privileges, and Delegated Administration
Use MySQL roles, default-role activation, dynamic privileges, role expansion, and controlled delegation to compose least-privilege access without global application grants.
Learning outcomes
Direct grants work for one account, but they become unmanageable when ServiceHub grows to many services and operators. Roles let you name privilege sets; dynamic privileges let MySQL split administrative powers that historically tended to accumulate in one superuser. The important nuance is that a role may be granted yet inactive in a particular session.
Distinguish global, database, table, column, and routine privilege scopes from dynamic administrative privileges.
Create roles, grant roles to accounts, choose default roles, and verify active-role state in a fresh connection.
Use SHOW GRANTS ... USING and CURRENT_ROLE() to distinguish assigned roles from effective privileges.
Explain why dynamic privileges reduce dependence on monolithic administrator privilege sets while remaining powerful global capabilities.
Delegate one role with WITH ADMIN OPTION without delegating unrelated role or account-management powers.
Privilege scope is part of the design
| Scope | Example | Design question |
|---|---|---|
| Global | CONNECTION_ADMIN, BACKUP_ADMIN | Does the actor really need a server-wide administrative capability? |
| Database | SELECT ON servicehub_security_lab.* | Should the actor see every object in this schema? |
| Table | UPDATE ON ...work_orders | Can the write surface be limited to one table? |
| Column | Column-specific SELECT/UPDATE | Is hiding/restricting individual columns stable enough to manage here? |
| Routine | EXECUTE ON PROCEDURE ... | Can a reviewed routine be a narrower API than direct table DML? |
A static privilege is built into the server privilege model. A dynamic privilege is registered at runtime, commonly by the server or a component, and is granted at global scope. Dynamic privileges such as CONNECTION_ADMIN, BACKUP_ADMIN, ROLE_ADMIN, or SET_ANY_DEFINER are not “safer because they are dynamic”; they are safer only when you grant the smallest one that matches the administrative job.
Create roles and keep them narrow
DROP ROLE IF EXISTS 'r_servicehub_reader', 'r_servicehub_writer';CREATE ROLE 'r_servicehub_reader', 'r_servicehub_writer';GRANT SELECTON servicehub_security_lab.sitesTO 'r_servicehub_reader';GRANT SELECTON servicehub_security_lab.work_ordersTO 'r_servicehub_reader';GRANT INSERT,UPDATEON servicehub_security_lab.work_ordersTO 'r_servicehub_writer';SHOW GRANTS FOR 'r_servicehub_reader';SHOW GRANTS FOR 'r_servicehub_writer';GRANT 'r_servicehub_reader','r_servicehub_writer'TO 'svc11_app'@'127.0.0.1';-- Chapter 01 used a direct grant for the initial lab. Remove it now so-- Chapter 11 tests role-based access rather than inherited direct access.REVOKE SELECT,INSERT,UPDATEON servicehub_security_lab.work_ordersFROM 'svc11_app'@'127.0.0.1';SHOW GRANTS FOR 'svc11_app'@'127.0.0.1';The final SHOW GRANTS proves that the roles are assigned; it does not by itself prove that their privileges are active in a new session. MySQL separates role assignment from role activation.
Wrong assumption: granted role means active role
SELECT USER(),CURRENT_USER(),CURRENT_ROLE();SELECT COUNT(*) FROM servicehub_security_lab.sites;-- If no default role is configured, activate a granted role explicitly:SET ROLE 'r_servicehub_reader';SELECT CURRENT_ROLE();SELECT COUNT(*) FROM servicehub_security_lab.sites;-- Return to the account defaults:SET ROLE DEFAULT;SELECT CURRENT_ROLE();If the account's default role is still NONE, the first query against sites can be denied even though an administrator previously granted the reader role. This is not a broken grant—it is an inactive role. Repair the account's login state deliberately:
SET DEFAULT ROLE 'r_servicehub_reader','r_servicehub_writer'TO 'svc11_app'@'127.0.0.1';SHOW GRANTS FOR 'svc11_app'@'127.0.0.1'USING 'r_servicehub_reader','r_servicehub_writer';SELECT @@global.activate_all_roles_on_login;By default, activate_all_roles_on_login is OFF, so default roles matter. Avoid turning on automatic activation globally simply to fix one account; that changes login privilege behavior for every account with granted roles.
Dynamic privileges: split administrative capability
SELECT GRANTEE,PRIVILEGE_TYPE,IS_GRANTABLEFROM INFORMATION_SCHEMA.USER_PRIVILEGESWHERE PRIVILEGE_TYPE IN ('CONNECTION_ADMIN','BACKUP_ADMIN','ROLE_ADMIN')ORDER BY GRANTEE,PRIVILEGE_TYPE;DROP ROLE IF EXISTS 'r_servicehub_operator';CREATE ROLE 'r_servicehub_operator';GRANT CONNECTION_ADMIN ON *.* TO 'r_servicehub_operator';SHOW GRANTS FOR 'r_servicehub_operator';CONNECTION_ADMIN is global and powerful; the lab grants it only to a role so the difference between an application role and an operator role is visible. You do not need to invoke disruptive operations to learn the model. The evidence is the role definition and a negative test proving the application account cannot perform operator actions.
A service account that needs table DML does not need CONNECTION_ADMIN, BACKUP_ADMIN, CREATE USER, ROLE_ADMIN, or WITH GRANT OPTION. Treat each of these as a separate escalation boundary.
Delegated administration with WITH ADMIN OPTION
DROP USER IF EXISTS 'svc11_teamlead'@'127.0.0.1';CREATE USER 'svc11_teamlead'@'127.0.0.1' IDENTIFIED BY 'LabOnly-TeamLead!2026';GRANT 'r_servicehub_reader'TO 'svc11_teamlead'@'127.0.0.1'WITH ADMIN OPTION;SET DEFAULT ROLE 'r_servicehub_reader'TO 'svc11_teamlead'@'127.0.0.1';SHOW GRANTS FOR 'svc11_teamlead'@'127.0.0.1';WITH ADMIN OPTION on a role means the grantee can grant or revoke that role to/from other accounts while the role is active; it does not grant arbitrary CREATE USER or unrelated privilege-management authority. That makes it a useful delegated boundary for a team lead who should manage membership in one approved role but not design new powers.
Production judgment
| Control | Prefer | Avoid |
|---|---|---|
| Application permissions | Roles containing explicit schema/table/routine privileges | Direct global grants to every service account |
| Default activation | Only the roles required for normal startup | Global activate_all_roles_on_login=ON as a convenience fix |
| Administrative capability | Specific dynamic privileges in operator roles | Using broad legacy superuser patterns |
| Delegation | WITH ADMIN OPTION for one role where governance supports it | WITH GRANT OPTION or ROLE_ADMIN without a documented need |
| Evidence | Fresh-session CURRENT_ROLE(), positive/negative tests, SHOW GRANTS ... USING | Assuming a GRANT statement changed an already-open session exactly as expected |
Hands-on role lab
- Create reader and writer roles and grant them to the application account.
- Connect fresh before setting defaults and record
CURRENT_ROLE(). - Activate the reader role manually and prove the read succeeds.
- Set reader+writer as default roles, reconnect, and verify both positive reads/writes and a negative
DROP. - Create the team-lead account with admin option only on the reader role.
- Record the operator role's dynamic privilege separately from application roles.
Knowledge check
- Does granting a role guarantee it is active in every session?
- What does
CURRENT_ROLE()show? - Why are dynamic privileges useful?
- What does
WITH ADMIN OPTIONdelegate? - Why use
SHOW GRANTS ... USING?
Reveal answers
- No. Role assignment and role activation are separate; default roles,
SET ROLE, and the global activation setting control effective roles. - The roles currently active in that session, or
NONE. - They split server-administration capabilities into named global powers that can be granted independently instead of relying on a monolithic administrator privilege.
- The ability to grant/revoke the specific role, not arbitrary MySQL privileges or account administration.
- It expands the privileges contributed by specified roles granted to the account, which helps audit effective role-based capability.
Summary and bridge to Lesson 3
Roles make privilege sets composable, but least privilege still depends on scope and job separation. Lesson 3 turns that into a separation-of-duties design: application, migration, backup, and operator responsibilities will be deliberately prevented from collapsing into one account.