When a client tries to connect to MySQL from a host that has no matching account entry, the server rejects the connection with:
ERROR 1130 (HY000): Host '203.0.113.42' is not allowed to connect to this MySQL server
The SQLSTATE is HY000 (general error), the condition name is ER_HOST_NOT_PRIVILEGED, and it is raised before authentication even completes — the server inspects the client's IP or hostname against the mysql.user table and drops the connection immediately if no row matches.
What This Error Means
MySQL access control is two-dimensional: every account is identified by both a username and a host. An account 'app'@'10.0.0.5' is entirely distinct from 'app'@'10.0.0.6'. When a client connects, MySQL resolves the client's IP address (and optionally performs a reverse DNS lookup to get the hostname), then queries mysql.user for a row where both User and Host match. If no row matches — even if the correct username and password are supplied — error 1130 is returned.
This is different from error 1045 (ER_ACCESS_DENIED_ERROR), which means a matching host entry was found but the password or authentication plugin failed. Error 1130 means no account for that host exists at all.
The host column in mysql.user supports wildcard patterns: % matches any host, and _ matches any single character. A common account like 'root'@'localhost' only permits connections from the local machine (via the Unix socket or 127.0.0.1), so connecting from any remote IP will trigger error 1130 unless a separate account exists for that host.
Common Causes
The MySQL user was created with
localhostonly. The defaultrootaccount and most accounts created without an explicit host clause use'localhost', which does not match remote TCP connections.Deploying to a new application server or container. The database was set up with hardcoded IP addresses or hostnames. When the application moves to a new server, the old host entry no longer matches.
Connecting via a load balancer or NAT gateway. The MySQL server sees the load balancer's egress IP, not the application server's IP. No account covers that IP.
Docker or Kubernetes networking. Container networking assigns dynamic IPs from a subnet (e.g.,
172.17.0.0/16) that was not anticipated when the MySQL account was created.Reverse DNS mismatch. MySQL performs a reverse DNS lookup on the connecting IP. If the resolved hostname does not match the
Hostpattern inmysql.user, the connection is rejected even if the IP itself would have matched a wildcard.Using
127.0.0.1vslocalhost. Connecting with--host=127.0.0.1forces a TCP connection, which matches'user'@'127.0.0.1'but not'user'@'localhost'(which uses the Unix socket).
How to Fix ER_HOST_NOT_PRIVILEGED
Check which accounts exist for the user.
Connect locally (on the MySQL server itself) and inspect existing accounts:
SELECT Host, User, plugin FROM mysql.user WHERE User = 'your_username';Create an account for the specific remote host.
If the application server has a stable IP:
CREATE USER 'app_user'@'203.0.113.42' IDENTIFIED BY 'strong_password'; GRANT SELECT, INSERT, UPDATE, DELETE ON mydb.* TO 'app_user'@'203.0.113.42'; FLUSH PRIVILEGES;Use a wildcard host to allow a subnet or any host.
For a private subnet:
CREATE USER 'app_user'@'10.0.0.%' IDENTIFIED BY 'strong_password'; GRANT SELECT, INSERT, UPDATE, DELETE ON mydb.* TO 'app_user'@'10.0.0.%'; FLUSH PRIVILEGES;To allow connections from any host (use only in trusted networks):
CREATE USER 'app_user'@'%' IDENTIFIED BY 'strong_password'; GRANT SELECT, INSERT, UPDATE, DELETE ON mydb.* TO 'app_user'@'%'; FLUSH PRIVILEGES;Add a host entry to an existing user without creating a new account.
If the user already exists for
localhostand you want to add a remote host:CREATE USER 'app_user'@'203.0.113.42' IDENTIFIED BY 'strong_password'; GRANT SELECT, INSERT, UPDATE, DELETE ON mydb.* TO 'app_user'@'203.0.113.42'; FLUSH PRIVILEGES;Note: in MySQL, each
user@hostcombination is a separate row; you cannot add a host to an existing account — you create a new account with the same username and different host.Disable reverse DNS lookups to avoid hostname mismatches.
If you suspect DNS resolution is causing a mismatch, add this to
my.cnfand restart:[mysqld] skip-name-resolveWhen
skip-name-resolveis enabled, MySQL only uses IP addresses for host matching. All existingHostentries that contain hostnames (not IPs or%) will stop matching, so audit yourmysql.usertable before making this change.Verify
bind-addressis not restricting connections.If MySQL is only listening on
127.0.0.1, remote clients cannot connect at all, and may receive error 1130 or a connection-refused TCP error. Inmy.cnf:[mysqld] bind-address = 0.0.0.0Restart MySQL after changing this. Also ensure your firewall allows inbound traffic on port 3306.
Additional Information
FLUSH PRIVILEGESis only needed when you modify the grant tables directly withINSERT/UPDATE. When usingGRANT,CREATE USER, orDROP USER, MySQL reloads privileges automatically.- MySQL 8.0 deprecated the
PASSWORD()function and changed the default authentication plugin tocaching_sha2_password. If an older client library does not support this plugin, change the account to usemysql_native_password:ALTER USER 'app_user'@'%' IDENTIFIED WITH mysql_native_password BY 'password'; - Related errors: 1045 (
ER_ACCESS_DENIED_ERROR) — host matched but credentials failed; 2003 — cannot connect to MySQL server at all (TCP refused, wrong port, orbind-addresstoo restrictive). - Cloud-managed MySQL (RDS, Cloud SQL, Azure Database for MySQL) typically requires using
%as the host, since the application connects over a VPC and the server sees a private IP rather thanlocalhost. - ORMs and connection pool libraries surface this as a generic connection error. In SQLAlchemy you will see
OperationalError: (MySQLdb.OperationalError) (1130, ...), and in Node.jsmysql2it will beError: ER_HOST_NOT_PRIVILEGED.
Frequently Asked Questions
Why does connecting as root from a remote machine fail even with the correct password?
The default root account is created as 'root'@'localhost', which only matches local socket connections. There is deliberately no 'root'@'%' account in a default MySQL installation for security reasons. Create a dedicated application user with the required host entry rather than enabling remote root access.
What is the difference between 'user'@'localhost' and 'user'@'127.0.0.1'?
localhost tells MySQL to use the Unix domain socket (or named pipe on Windows), bypassing TCP entirely. 127.0.0.1 forces a TCP connection to the loopback interface. They are treated as two different hosts. If you connect with mysql -h 127.0.0.1 and get error 1130, your account may only have a localhost entry.
Is it safe to use '%' as the host?
The % wildcard is appropriate when your network is already controlled — for example, a private VPC where MySQL is not exposed to the public internet. If MySQL is publicly accessible, use specific IP addresses or CIDR-style patterns (10.0.0.%) and ensure a strong password and TLS are in place.
I added the user with GRANT ... TO 'user'@'%' but still get error 1130. What else could be wrong?
Check that: (1) you ran FLUSH PRIVILEGES if you modified grant tables directly, (2) the bind-address in my.cnf is set to 0.0.0.0 or the server's external IP, (3) your firewall or security group allows inbound TCP on port 3306, and (4) skip-name-resolve is set if DNS resolution is returning an unexpected hostname for your client IP.