Skip to main content
Blog|
How-to guides

How to show and manage MySQL users

|
Mar 27, 2026|10 min read
HOW-TO GUIDESHow to show and manage MySQLusersHOSTNEYhostney.comMarch 27, 2026

MySQL user management is one of those tasks that is straightforward once you know the commands but confusing the first time because MySQL’s user model has a quirk that most other systems do not: a user is defined by both a username and a host. wp_user@localhost and wp_user@10.0.1.50 are two completely different users with separate passwords and separate privileges. Understanding this host component is the key to everything in this guide.

This is a practical reference for listing users, checking privileges, creating users, changing passwords, and managing access. Each section is self-contained so you can jump to the operation you need.

Listing all MySQL users#

Basic user list

SELECT User, Host FROM mysql.user;

Output:

+------------------+-----------+
| User             | Host      |
+------------------+-----------+
| root             | localhost |
| mysql.infoschema | localhost |
| mysql.session    | localhost |
| mysql.sys        | localhost |
| wp_user          | localhost |
| wp_user          | 127.0.0.1 |
| shop_user        | localhost |
+------------------+-----------+

The mysql.user table is the authoritative source of all MySQL users. The system accounts ( mysql.infoschema , mysql.session , mysql.sys ) are internal to MySQL and should not be modified.

Notice that wp_user appears twice – once for localhost and once for 127.0.0.1 . These are separate users. On most systems, connecting via localhost uses a Unix socket, while 127.0.0.1 uses TCP. Some applications use one, some use the other, so it is common to create both.

User list with authentication details

SELECT User, Host, plugin, authentication_string
FROM mysql.user
WHERE User NOT LIKE 'mysql.%';

This excludes system accounts and shows which authentication plugin each user uses. On MySQL 8.0+, the default plugin is caching_sha2_password . Older installations may use mysql_native_password .

Count users

SELECT COUNT(*) AS total_users FROM mysql.user WHERE User NOT LIKE 'mysql.%';

Filter by pattern

-- All users starting with "wp"
SELECT User, Host FROM mysql.user WHERE User LIKE 'wp%';

-- All users that can connect from any host
SELECT User, Host FROM mysql.user WHERE Host = '%';

-- All non-root, non-system users
SELECT User, Host FROM mysql.user
WHERE User NOT IN ('root') AND User NOT LIKE 'mysql.%';

Checking user privileges#

SHOW GRANTS

View the privileges for a specific user:

SHOW GRANTS FOR 'wp_user'@'localhost';

Output:

+----------------------------------------------------------------+
| Grants for wp_user@localhost                                   |
+----------------------------------------------------------------+
| GRANT USAGE ON *.* TO `wp_user`@`localhost`                    |
| GRANT ALL PRIVILEGES ON `wordpress_db`.* TO `wp_user`@`localhost` |
+----------------------------------------------------------------+

Reading the output:

  • GRANT USAGE ON *.*  means the user can connect to MySQL but has no global privileges. Every user has this.  USAGE  essentially means “no privileges.”
  • GRANT ALL PRIVILEGES ON wordpress_db.*  means full access to every table in the  wordpress_db  database.

Check grants for the current user

SHOW GRANTS;

or:

SHOW GRANTS FOR CURRENT_USER();

List all users with their database access

SELECT grantee, table_schema, privilege_type
FROM information_schema.SCHEMA_PRIVILEGES
ORDER BY grantee, table_schema;

This shows which users have access to which databases and what type of access they have. Useful for auditing permissions across the server.

Check if a user has a specific privilege

SELECT *
FROM information_schema.USER_PRIVILEGES
WHERE GRANTEE = "'wp_user'@'localhost'";

Creating users#

Basic user creation

CREATE USER 'new_user'@'localhost' IDENTIFIED BY 'strong_password_here';

This creates a user who can connect from localhost only, with no privileges on any database. You must grant privileges separately.

Create user with specific authentication plugin

MySQL 8.0+ defaults to caching_sha2_password , which some older PHP versions and MySQL client libraries do not support. If you get authentication errors when connecting from WordPress or other PHP applications, create the user with the older plugin:

CREATE USER 'new_user'@'localhost'
  IDENTIFIED WITH mysql_native_password BY 'strong_password_here';

This is a compatibility measure, not a security recommendation. caching_sha2_password is more secure. Use mysql_native_password only if the connecting application does not support the newer plugin.

Create user if not exists

CREATE USER IF NOT EXISTS 'new_user'@'localhost' IDENTIFIED BY 'strong_password_here';

Prevents errors in scripts that may run multiple times.

Create user for remote access

CREATE USER 'remote_user'@'10.0.1.50' IDENTIFIED BY 'strong_password_here';

This user can only connect from IP 10.0.1.50 . For a complete guide to setting up remote MySQL access including firewall configuration and SSL requirements, see How to allow remote MySQL connections.

The host component explained

The @'host' part of a MySQL user determines where connections are accepted from:

Host valueMeaning
localhost Local connections via Unix socket
127.0.0.1 Local connections via TCP
10.0.1.50 Only from this specific IP
10.0.1.% Any IP in the 10.0.1.x subnet
%.example.com Any host in the example.com domain
% Any host (dangerous in production)

MySQL evaluates host matches from most specific to least specific. If both wp_user@10.0.1.50 and wp_user@% exist, a connection from 10.0.1.50 matches the more specific entry.

Never use @'%' in production unless the user also requires SSL and you have firewall rules limiting access to port 3306. An @'%' user with a weak password is one of the most common vectors for MySQL compromise.

Granting privileges#

Grant all privileges on a database

GRANT ALL PRIVILEGES ON wordpress_db.* TO 'wp_user'@'localhost';
FLUSH PRIVILEGES;

ALL PRIVILEGES includes: SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, INDEX, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EXECUTE, REFERENCES, and more. For WordPress, this is the standard grant.

Grant specific privileges

For tighter security, grant only what the application needs:

GRANT SELECT, INSERT, UPDATE, DELETE ON wordpress_db.* TO 'wp_user'@'localhost';
FLUSH PRIVILEGES;

This is sufficient for WordPress during normal operation (reading and writing posts, comments, options). However, WordPress needs CREATE, ALTER, and DROP during plugin installations, theme installations, and core updates (which create and modify tables). If you restrict to only SELECT/INSERT/UPDATE/DELETE, plugin installations will fail.

A practical middle ground for WordPress:

GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, INDEX
  ON wordpress_db.* TO 'wp_user'@'localhost';
FLUSH PRIVILEGES;

This covers all WordPress operations without granting administrative privileges like GRANT OPTION, PROCESS, or FILE.

Grant on a specific table

GRANT SELECT ON wordpress_db.wp_posts TO 'readonly_user'@'localhost';

Useful for reporting tools or read-only API users that should only access specific tables.

Grant with GRANT OPTION

GRANT ALL PRIVILEGES ON wordpress_db.* TO 'admin_user'@'localhost' WITH GRANT OPTION;

WITH GRANT OPTION allows this user to grant their own privileges to other users. Do not give this to application users – only to administrative accounts.

Revoking privileges#

Revoke specific privileges

REVOKE DROP, ALTER ON wordpress_db.* FROM 'wp_user'@'localhost';
FLUSH PRIVILEGES;

Revoke all privileges

REVOKE ALL PRIVILEGES ON wordpress_db.* FROM 'wp_user'@'localhost';
FLUSH PRIVILEGES;

The user still exists and can connect, but has no access to any database. You would typically follow this with new, more appropriate grants.

Verify after revoking

SHOW GRANTS FOR 'wp_user'@'localhost';

Always verify that the revoke worked as expected. MySQL privilege inheritance can be subtle, and global grants take precedence over database-level grants.

Changing passwords#

ALTER USER (MySQL 8.0+ recommended method)

ALTER USER 'wp_user'@'localhost' IDENTIFIED BY 'new_strong_password';
FLUSH PRIVILEGES;

SET PASSWORD (older method, still works)

SET PASSWORD FOR 'wp_user'@'localhost' = 'new_strong_password';

In MySQL 8.0+, SET PASSWORD internally calls ALTER USER .

Change your own password

ALTER USER CURRENT_USER() IDENTIFIED BY 'new_strong_password';

Force password expiration

ALTER USER 'wp_user'@'localhost' PASSWORD EXPIRE;

The user can still connect but must change their password before running any queries. Useful for forcing a password rotation.

After changing a MySQL password

If you change the password for a user that WordPress connects with, update wp-config.php immediately:

define('DB_PASSWORD', 'new_strong_password');

Forgetting this step results in “Error establishing a database connection” – see Error establishing a database connection in WordPress: how to fix it.

Renaming users#

RENAME USER 'old_name'@'localhost' TO 'new_name'@'localhost';

This changes the username while preserving all privileges. You can also change the host:

RENAME USER 'wp_user'@'localhost' TO 'wp_user'@'10.0.1.50';

This effectively moves the user from local-only to remote access from a specific IP. Privileges are preserved.

Deleting users#

DROP USER

DROP USER 'wp_user'@'localhost';

This removes the user and all their privileges. The user can no longer connect. Databases and tables the user created are not affected – only the user account is removed.

Drop with IF EXISTS

DROP USER IF EXISTS 'wp_user'@'localhost';

Drop both localhost entries

If you created a user for both localhost and 127.0.0.1 (common practice), drop both:

DROP USER IF EXISTS 'wp_user'@'localhost';
DROP USER IF EXISTS 'wp_user'@'127.0.0.1';

Before dropping a user

Check if any application is using the credentials. Dropping a user that WordPress connects with immediately causes “Error establishing a database connection” for every visitor. Always update or remove the application configuration first.

Locking and unlocking accounts#

MySQL 8.0+ supports account locking, which prevents login without deleting the user:

-- Lock (prevent connections)
ALTER USER 'wp_user'@'localhost' ACCOUNT LOCK;

-- Unlock (allow connections again)
ALTER USER 'wp_user'@'localhost' ACCOUNT UNLOCK;

Locking is useful when you need to temporarily disable access without losing the user’s privilege configuration.

Checking connected users#

Currently connected users

SELECT User, Host, db, Command, Time
FROM information_schema.PROCESSLIST
WHERE User NOT IN ('system user', 'event_scheduler');

or the shorthand:

SHOW PROCESSLIST;

This shows who is connected right now, which database they are using, what command they are running, and how long they have been running it. Useful for identifying connection leaks or long-running queries.

Kill a connection

If a connection is stuck:

KILL connection_id;

The connection ID is in the Id column of SHOW PROCESSLIST .

Security best practices for MySQL users#

Principle of least privilege

Give each user only the privileges they need. A WordPress user does not need PROCESS (server status), FILE (read/write files on the server), or SUPER (administrative operations). These privileges can be exploited if the credentials are compromised.

One user per application

Do not share MySQL users between different WordPress installations or different applications. If one application is compromised, the attacker only has access to that application’s database, not every database on the server.

No anonymous users

Check for and remove anonymous users (users with an empty username):

SELECT User, Host FROM mysql.user WHERE User = '';

If any exist:

DROP USER ''@'localhost';

Anonymous users are created by some MySQL installation scripts and allow anyone to connect without credentials. The mysql_secure_installation script removes them.

Regular audits

Periodically check for users with excessive privileges:

-- Users with global ALL PRIVILEGES (dangerous)
SELECT User, Host FROM mysql.user WHERE Super_priv = 'Y' AND User != 'root';

-- Users who can connect from any host
SELECT User, Host FROM mysql.user WHERE Host = '%';

-- Users with GRANT OPTION
SELECT User, Host FROM mysql.user WHERE Grant_priv = 'Y' AND User != 'root';

How Hostney handles MySQL users#

On Hostney, MySQL users are managed through the control panel under Hosting > MySQL Users.

Local users. The system creates each user with access from both localhost and 127.0.0.1 , covering both Unix socket and TCP connections. Usernames are auto-generated with a unique pattern to prevent collisions across accounts on the same server.

Passwords. Passwords are auto-generated with a minimum of 16 characters using alphanumeric characters. You can change the password at any time through the control panel, and the new password takes effect immediately.

Access management. You assign users to databases through Hosting > MySQL Access. This is a many-to-many relationship: one user can access multiple databases, and one database can be accessed by multiple users. Each assignment creates the appropriate GRANT statements on the MySQL server.

External users. For remote database access, the control panel provides a separate section under Hosting > MySQL External Users. External users require SSL for all connections and are restricted to specific IP addresses that you configure. The system automatically manages firewall rules to allow MySQL connections from those IPs. See How to allow remote MySQL connections for the complete setup.

Per-account isolation. Each hosting account’s users are isolated from other accounts. You cannot see or manage users belonging to other accounts, even on the same MySQL server. This isolation is enforced at both the application level (the API scopes by customer ID) and the MySQL privilege level.

Size-based permission changes. When a database exceeds its size limit, the system automatically changes user privileges on that database from ALL PRIVILEGES to SELECT and DELETE only. This lets the site continue reading existing data and lets you delete data to free up space, but prevents new inserts until the database is back under its limit.

Summary#

MySQL users are defined by a username and host combination. List users with SELECT User, Host FROM mysql.user , check privileges with SHOW GRANTS FOR , create with CREATE USER , grant access with GRANT , and remove with DROP USER . Always specify the host when creating or managing users, and never use @'%' in production without additional security measures.

The most common mistake is creating a user and forgetting to grant privileges, or granting privileges on the wrong host. Always verify with SHOW GRANTS after any change. For creating the databases these users access, see How to create a database in MySQL. For listing and inspecting those databases, see How to show databases in MySQL.