Skip to main content

Database User Privileges (WordPress VPS)

WordPress needs a database user with enough privileges to create and modify tables during installs and updates, but it should not run as a full admin user. Use least privilege: a dedicated WordPress DB user scoped to the WordPress database. This reduces the impact of compromised credentials and prevents accidental admin operations.

Quick Summary

Create a dedicated user like 'wpuser'@'localhost', grant it privileges only on wordpress.*, then verify with SHOW GRANTS.

warning

Do not use the database root user in wp-config.php. If WordPress is compromised, a root DB user makes the incident far worse.

Mental Model

Prerequisites

  • Admin access to MySQL/MariaDB (typically root).
  • Ability to run mysql commands.

Common WordPress Privileges

WordPress typically needs privileges to read/write data and manage schema changes. Common privileges include:

  • SELECT, INSERT, UPDATE, DELETE
  • CREATE, DROP, ALTER, INDEX
  • CREATE TEMPORARY TABLES, LOCK TABLES

Exact needs vary by plugins and tooling.

Examples (Commands + Expected Output)

Output varies

Privileges and authentication plugins vary by MySQL/MariaDB version.

List database users (admin)

list-db-users.sh
mysql -u root -p -e "SELECT user, host FROM mysql.user ORDER BY user, host;"

Expected output (excerpt):

example-output-mysql-users.txt
user host
root localhost
wpuser localhost

Use case: Audit which accounts exist.

Show grants for the WordPress user

show-grants-for-wpuser.sh
mysql -u root -p -e "SHOW GRANTS FOR 'wpuser'@'localhost';"

Expected output:

example-output-show-grants.txt
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, INDEX ON `wordpress`.* TO `wpuser`@`localhost`

Use case: Confirm least-privilege scope.

Create a dedicated WordPress user

create-wordpress-user.sql
mysql -u root -p -e "CREATE USER 'wpuser'@'localhost' IDENTIFIED BY 'REPLACE_ME_WITH_A_STRONG_PASSWORD';"

Expected output:

example-output-create-user.txt
(no output on success)

Use case: Create a dedicated user for the application.

Grant WordPress privileges (scoped to one database)

grant-wordpress-privileges.sql
mysql -u root -p -e "GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, INDEX, CREATE TEMPORARY TABLES, LOCK TABLES ON wordpress.* TO 'wpuser'@'localhost';"

Expected output:

example-output-grant.txt
(no output on success)

Use case: Allow WordPress to install/update and operate normally.

Create a read-only user for reporting

create-readonly-user.sql
mysql -u root -p -e "CREATE USER 'wpreadonly'@'localhost' IDENTIFIED BY 'REPLACE_ME'; GRANT SELECT ON wordpress.* TO 'wpreadonly'@'localhost';"

Expected output:

example-output-readonly.txt
(no output on success)

Use case: Give a developer/reporting job safe read-only access.

Revoke privileges (cleanup)

revoke-privileges.sql
mysql -u root -p -e "REVOKE ALL PRIVILEGES, GRANT OPTION FROM 'wpuser'@'localhost';"

Expected output:

example-output-revoke.txt
(no output on success)

Use case: Remove access when rotating credentials or decommissioning.

caution

Avoid using 'wpuser'@'%' (any host) unless you really need remote connections. Prefer localhost or a specific host/IP.

WordPress VPS Use Cases

ScenarioRecommended userWhy
Normal WP operationwpuser@localhostLimits blast radius
Scheduled reportingwpreadonly@localhostPrevents accidental writes
Migration toolingTemporary user with required privilegesRotate/remove after migration

Troubleshooting

ErrorLikely causeFix
Access deniedWrong password or host mismatchConfirm 'user'@'host' matches connection source
WP asks for FTP credentialsDB user OK, filesystem perms notCheck Linux ownership/permissions (separate topic)
Plugins fail to create tablesMissing schema privilegesAdd CREATE/ALTER/INDEX on wordpress.*

Best Practices

  • Keep WordPress DB user scoped to a single database.
  • Rotate DB passwords during incident response.
  • Audit grants periodically with SHOW GRANTS.
Cheat Sheet
db-users-cheat-sheet.sql
-- list users
SELECT user, host FROM mysql.user;

-- show grants
SHOW GRANTS FOR 'wpuser'@'localhost';

-- create user
CREATE USER 'wpuser'@'localhost' IDENTIFIED BY 'REPLACE_ME';

-- grant scoped privileges
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, INDEX, CREATE TEMPORARY TABLES, LOCK TABLES
ON wordpress.* TO 'wpuser'@'localhost';

-- revoke
REVOKE ALL PRIVILEGES, GRANT OPTION FROM 'wpuser'@'localhost';

What's Next