How to grant a user access to a database
A database user with no privileges cannot do anything, and one with too many is a risk you do not need to take.
A MySQL user that exists but has not been granted any privileges on a database cannot read a single row from it. Privileges are what turn a login into actual access, and they are granted separately from creating the user in the first place — see creating a MySQL database and user if you have not done that part yet. This guide covers attaching an existing user and choosing what it is allowed to do.
Why the privilege level is worth thinking about
It is tempting to grant every user full access to every database it touches and move on, and for a small personal project that is often harmless. On an account running several applications, or one handling anything sensitive, it is worth a moment's thought instead. A user restricted to only the privileges its application genuinely needs limits what could go wrong if that application is ever compromised through a bug in its own code — see what SQL injection is for a concrete example of why this matters in practice, not just in theory.
A dedicated user per database, scoped to what that specific application needs, contains a problem to the database it happened on. A single shared user with access to every database gives a compromise in one application a path into all of them.
The privilege levels worth knowing
MySQL privileges are more granular than most applications need, but a handful come up repeatedly:
| Privilege | What it allows |
|---|---|
SELECT | Read rows. Enough for reporting tools, read-only dashboards, or a backup script. |
INSERT | Add new rows. |
UPDATE | Change existing rows. |
DELETE | Remove rows. |
CREATE, ALTER, DROP, INDEX | Change the structure of tables. Needed by an application's own installer, rarely needed afterwards. |
ALL PRIVILEGES | Everything above, on the named database. The usual choice for an application you are installing yourself. |
Most off-the-shelf software, including WordPress, expects ALL PRIVILEGES on its own database during installation and for as long as you plan to run automatic updates, since updates sometimes alter table structure. A user for a reporting tool or a read-only integration usually needs nothing beyond SELECT.
Granting access from your control panel
The databases section of your control panel is the straightforward route for most cases. Find the database, find the option to manage its users, and either add an existing user or select one you have already created. You will usually be offered a privilege level to choose from a list rather than ticking individual privileges, with "all privileges" as one option and a more restricted set as another. This is enough for the overwhelming majority of setups and does not require writing any SQL at all.
Granting access with SQL directly
If you need more precise control than the panel exposes, phpMyAdmin's SQL tab, or any client connected to the database, accepts the GRANT statement directly. To grant full access to a specific database:
GRANT ALL PRIVILEGES ON database_name.* TO 'username'@'localhost';
FLUSH PRIVILEGES;
To grant a narrower set instead, list only the privileges the application needs:
GRANT SELECT, INSERT, UPDATE, DELETE ON database_name.* TO 'username'@'localhost';
FLUSH PRIVILEGES;
For a genuinely read-only user, such as one used for reporting or for an automated backup script:
GRANT SELECT ON database_name.* TO 'username'@'localhost';
FLUSH PRIVILEGES;
Replace database_name and username with your actual values, including any account prefix your control panel adds automatically. The @'localhost' part matters: it says this grant applies when the user connects from the same server the database is on, which is the normal case on shared hosting — see why the database host is "localhost" if that looks unfamiliar.
Changes made through your control panel take effect immediately. FLUSH PRIVILEGES is only necessary after editing the underlying grant tables directly with SQL, which is exactly what a manual GRANT or REVOKE statement does. Running it after a panel change is harmless, just unnecessary.
Reducing an existing user's privileges
Taking privileges away from a user that already has them is done with REVOKE, using the same structure:
REVOKE INSERT, UPDATE, DELETE ON database_name.* FROM 'username'@'localhost';
FLUSH PRIVILEGES;
Removing a privilege an application actually relies on, even one that looks unused, will break it the moment it next tries to use that privilege. Take a full backup before revoking anything from a user attached to a live site, and test thoroughly straight afterwards. See exporting a database if you need a quick backup before making this kind of change.
Checking what a user currently has
To see the privileges already granted to a specific user, run:
SHOW GRANTS FOR 'username'@'localhost';
This is worth running before changing anything on a user you did not set up yourself, so you know what you are about to alter rather than guessing.
Testing after any change
Whichever route you used, load the application afterwards and exercise the parts of it that touch the database: logging in, saving a change, anything that writes data if the user is meant to be able to write. A privilege change that looks correct on paper occasionally misses something the application needs, and it is far easier to catch that immediately than to trace it back from an obscure error days later. Connecting an application to MySQL covers the connection code itself if the failure turns out to be there rather than in the privileges.
If a privilege change has broken something and you cannot work out which privilege is missing, contact us with the database name and what the application was doing when it failed, and we can check the grants directly.
Related reading
Every application needs a database, a user, and that user attached to the database — here is the order to do it in.
How to connect an application to MySQLEvery MySQL connection, in any language, comes down to the same four values — here is where to find them and how to use them.
What SQL injection is, and how sites get hitA decades-old vulnerability that still appears in new code, and the small set of habits that reliably prevent it.
How to reset a database user passwordResetting the password is the easy part — updating every application that still has the old one saved is the part people forget.