Safeguard
Security Guides•

MySQL roles: set up least privilege app accounts in 8.4

Use MySQL roles to give app accounts read or write access to one schema. Covers CREATE ROLE, GRANT, SET DEFAULT ROLE and locked role behavior.

Safeguard Security Team
2 min read

In MySQL 8.4, create a role per access level, grant privileges to the role, then grant the role to accounts. Granting a role does not activate it, so run SET DEFAULT ROLE as well. Roles are locked by default and cannot log in, which suits them as permission bundles for application accounts.

Create and grant

CREATE ROLE 'app_read', 'app_write';

GRANT SELECT ON app_db.* TO 'app_read';
GRANT INSERT, UPDATE, DELETE ON app_db.* TO 'app_write';

GRANT 'app_read' TO 'report_user'@'10.0.0.%';
GRANT 'app_read', 'app_write' TO 'api_user'@'10.0.0.%';

Privilege grants and role grants cannot be mixed in one statement. Role names default to host % if you omit the host, and the manual says roles cannot be granted to anonymous users.

Activate the roles

A granted role is not active until you say so:

SET DEFAULT ROLE ALL TO 'report_user'@'10.0.0.%', 'api_user'@'10.0.0.%';

Before defaults are set, SELECT CURRENT_ROLE(); returns NONE. Within a session, SET ROLE can narrow the active set, for example SET ROLE NONE;. The variable activate_all_roles_on_login is off by default. When on, all granted roles activate at login whatever SET DEFAULT ROLE says. Keep it off if you want explicit control.

Locked by default

A new role is locked, has no password and uses the default authentication plugin. A locked role cannot authenticate. CREATE USER creates an unlocked account, which is the main difference. That means a stray role cannot become a back door, unless someone unlocks it with ALTER USER.

One change fixes many accounts

Privileges on a role affect every account holding it. Revoking write privileges from app_write makes all of its holders read-only at once. This beats auditing dozens of individual grants.

Related guidance

The MySQL security guidelines tell you to grant no more privileges than necessary and never to grant privileges to all hosts. Audit with SHOW GRANTS and remove excess with REVOKE. See the MySQL hardening checklist.

Quick check

I granted a role but the user sees no privileges. Why?

The role is probably not active. Use SET DEFAULT ROLE for the account, or enable activate_all_roles_on_login if you accept auto activation of all granted roles.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.