SQL GRANT Statement
GRANT gives an account (or a role) permission to do something: read a table, insert rows, create tables, run a procedure. It is the core of DCL (Data Control Language). Granting exactly what each account needs, and nothing more, is the most effective database security measure you can take.
- Grant privileges at global, database, table and column level
- Inspect privileges with
SHOW GRANTS - Grant through views for row and column security
- Understand
WITH GRANT OPTIONandALL PRIVILEGES
GRANT syntax
GRANT privilege [, privilege ...]ON levelTO 'user'@'host' [, ...][WITH GRANT OPTION];| Level | Written as | Example |
|---|---|---|
| Global | . | every database on the server |
| Database | company.* | every table in company |
| Table | company.orders | one table |
| Column | SELECT (col1, col2) ON company.employees | some columns of one table |
| Routine | EXECUTE ON PROCEDURE company.place_order | one procedure |
Common privileges: SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, DROP, INDEX, EXECUTE, CREATE VIEW, TRIGGER, and ALL PRIVILEGES.
Database-level grant
CREATE USER 'shop_app'@'localhost' IDENTIFIED BY 'Sh0p#App2026';GRANT SELECT, INSERT, UPDATE, DELETE ON company.* TO 'shop_app'@'localhost';SHOW GRANTS FOR 'shop_app'@'localhost';| Grants for shop_app@localhost |
|---|
| GRANT USAGE ON *.* TO `shop_app`@`localhost` |
| GRANT SELECT, INSERT, UPDATE, DELETE ON `company`.* TO `shop_app`@`localhost` |
- The account can read and change rows in every table of
company. - It cannot create, alter or drop tables, and it cannot touch other databases.
SHOW GRANTSlists exactly what the account may do.
Table-level grant
A reporting account that may read only the shop tables:
CREATE USER 'report_reader'@'localhost' IDENTIFIED BY 'Rep0rt#2026';GRANT SELECT ON company.orders TO 'report_reader'@'localhost';GRANT SELECT ON company.order_items TO 'report_reader'@'localhost';GRANT SELECT ON company.products TO 'report_reader'@'localhost';SHOW GRANTS FOR 'report_reader'@'localhost';| Grants for report_reader@localhost |
|---|
| GRANT USAGE ON *.* TO `report_reader`@`localhost` |
| GRANT SELECT ON `company`.`order_items` TO `report_reader`@`localhost` |
| GRANT SELECT ON `company`.`orders` TO `report_reader`@`localhost` |
| GRANT SELECT ON `company`.`products` TO `report_reader`@`localhost` |
Column-level grant
HR assistants may see employee names and departments, but not salaries:
CREATE USER 'hr_assistant'@'localhost' IDENTIFIED BY 'Hr#Asst2026';GRANT SELECT (emp_id, first_name, last_name, dept_id, job_title) ON company.employees TO 'hr_assistant'@'localhost';GRANT UPDATE (job_title) ON company.employees TO 'hr_assistant'@'localhost';SHOW GRANTS FOR 'hr_assistant'@'localhost';| Grants for hr_assistant@localhost |
|---|
| GRANT USAGE ON *.* TO `hr_assistant`@`localhost` |
| GRANT SELECT (`dept_id`, `emp_id`, `first_name`, `job_title`, `last_name`), UPDATE (`job_title`) ON `company`.`employees` TO `hr_assistant`@`localhost` |
SELECT (columns)allows reading only the listed columns;SELECT salary FROM employeeswould fail for this account.UPDATE (job_title)allows changing that one column only.
Security through views
Column grants cannot filter rows. A view can: give a regional manager only Mumbai employees:
CREATE VIEW mumbai_staff ASSELECT emp_id, first_name, last_name, job_title FROM employees WHERE city = 'Mumbai';CREATE USER 'mumbai_mgr'@'localhost' IDENTIFIED BY 'Mumb@i#2026';GRANT SELECT ON company.mumbai_staff TO 'mumbai_mgr'@'localhost';SHOW GRANTS FOR 'mumbai_mgr'@'localhost';| Grants for mumbai_mgr@localhost |
|---|
| GRANT USAGE ON *.* TO `mumbai_mgr`@`localhost` |
| GRANT SELECT ON `company`.`mumbai_staff` TO `mumbai_mgr`@`localhost` |
The account can read the view but has no privilege on employees itself (Views).
Grant to a role
CREATE ROLE 'qa_tester';GRANT SELECT, INSERT, UPDATE, DELETE ON company.* TO 'qa_tester';CREATE USER 'arjun'@'localhost' IDENTIFIED BY 'Arj#un2026';GRANT 'qa_tester' TO 'arjun'@'localhost';SHOW GRANTS FOR 'arjun'@'localhost';| Grants for arjun@localhost |
|---|
| GRANT USAGE ON *.* TO `arjun`@`localhost` |
| GRANT `qa_tester`@`%` TO `arjun`@`localhost` |
See Users & Roles.
WITH GRANT OPTION and ALL PRIVILEGES
WITH GRANT OPTIONlets the account pass its own privileges on to others. Give it only to administrators.GRANT ALL PRIVILEGES ON company.* TO ...gives every database-level privilege, includingDROP. Convenient for a developer’s own test database, dangerous for an application account.
CREATE USER 'team_lead'@'localhost' IDENTIFIED BY 'L3ad#2026';GRANT ALL PRIVILEGES ON company.* TO 'team_lead'@'localhost' WITH GRANT OPTION;SHOW GRANTS FOR 'team_lead'@'localhost';| Grants for team_lead@localhost |
|---|
| GRANT USAGE ON *.* TO `team_lead`@`localhost` |
| GRANT ALL PRIVILEGES ON `company`.* TO `team_lead`@`localhost` WITH GRANT OPTION |
Errors
Granting on an account that does not exist fails in MySQL 8 (older versions silently created it):
GRANT SELECT ON company.* TO 'ghost'@'localhost';ERROR 1410 (42000): You are not allowed to create a user with GRANT
Quick quiz
1. What does ON company.* mean?
db.* is the database level.
2. How do you let an account read only some columns of a table?
Column privileges list the columns in parentheses.
3. Which tool restricts which rows an account can see?
Grant SELECT on the view instead of the table.
4. What does WITH GRANT OPTION allow?
Give it only to trusted administrators.
GRANT FAQ
What is the GRANT command in SQL?
A Data Control Language statement that gives privileges, such as SELECT or INSERT, on databases, tables, columns or routines to accounts or roles.
How do I see the privileges of a MySQL user?
SHOW GRANTS FOR 'user'@'host'; For your own account, SHOW GRANTS;.
Do I need FLUSH PRIVILEGES after GRANT?
No. GRANT, REVOKE, CREATE USER and similar statements take effect immediately. FLUSH PRIVILEGES is only needed after editing the grant tables directly, which you should not do.