You try to connect to your database from your laptop, a second server, or an app, and MySQL answers with: ERROR 1130 (HY000): Host '203.0.113.25' is not allowed to connect to this MySQL server. The password isn't even being checked at this point. The server is telling you it doesn't know your machine at all. Here's how to find out why and fix it without opening your database to the whole internet.
What error 1130 actually means
MySQL and MariaDB identify an account by two things: the username and the host it connects from. app_user@localhost and app_user@203.0.113.25 are two completely different accounts. Error 1130 means no account entry matches the host you're connecting from.
It's easy to confuse with error 1045 (access denied). The difference is simple:
| Error | Meaning | Usual fix |
|---|---|---|
| 1130 | Your host has no matching account at all | Create or change the account's host, or connect from an allowed host |
| 1045 | Account matched, but password or privileges are wrong | Reset the password, check grants |
| 2002 / 2003 | Can't reach the server at all (socket or network) | Check the service, bind address and firewall |
Common causes
- The user was created only for
localhost, and you're connecting remotely. - Your public IP changed (home broadband, mobile hotspot) and the old grant no longer matches.
- You're connecting from another server, but the grant lists its public IP while MySQL sees its private IP (or the reverse).
- Docker or a NAT layer is changing the source address, so MySQL sees something like
172.17.0.1. skip-name-resolveis on, so a grant written with a hostname like%.example.comnever matches.
Step 1: Find out what host MySQL actually sees
Don't guess the IP. Check the error message, because it prints the exact host MySQL saw. On the server, you can also check the live view:
mysql -u root -p -e "SELECT user, host FROM mysql.user ORDER BY user;"
If you can connect locally from some account, run this from the failing client to see what the server records:
SELECT USER(), CURRENT_USER();
Compare the host in the error with the host column. If your user only appears with localhost or 127.0.0.1, that's your answer.
Step 2: Fix it on a VPS (root access)
Log in as root and create a grant for the specific IP. Use the narrowest host you can.
mysql -u root -p
CREATE USER 'app_user'@'203.0.113.25' IDENTIFIED BY 'a-strong-password-here';
GRANT SELECT, INSERT, UPDATE, DELETE ON appdb.* TO 'app_user'@'203.0.113.25';
FLUSH PRIVILEGES;
If the user already exists for localhost and you just want the same account to work from one more address, you still create a second entry. MySQL won't extend an existing one. To rename the host of an existing account instead:
RENAME USER 'app_user'@'localhost' TO 'app_user'@'203.0.113.25';
Be careful with that one, because the app running on the same server will stop working if it still connects through localhost.
Avoid the lazy fix
You'll see advice online to use 'app_user'@'%'. That allows any IP on earth to attempt a login. It works, but it's the reason so many exposed databases get brute-forced. If your IP isn't static, use a subnet like 'app_user'@'203.0.113.%', or better, tunnel over SSH (below).
Step 3: Check the server is listening for remote connections
If you fixed the grant and now get a timeout instead of 1130, that's progress. It means the network layer is the next hurdle. Check the bind address:
grep -R "bind-address" /etc/mysql/ /etc/my.cnf /etc/my.cnf.d/ 2>/dev/null
ss -tlnp | grep 3306
If it shows 127.0.0.1:3306, MySQL only listens locally. Change bind-address to the server's private IP (preferred) or 0.0.0.0, restart the service, and then allow only your client IP through the firewall:
sudo ufw allow from 203.0.113.25 to any port 3306 proto tcp
Never open 3306 to everyone. If you use CSF or firewalld, add the equivalent source-restricted rule.
Step 4: Fix it on cPanel shared hosting
On cpanel" class="auto-link">wordpress-missing-a-temporary-folder-upload-error" class="auto-link">cPanel you don't edit mysql.user directly. Use the interface:
- Log in to cPanel and open Remote MySQL (under Databases).
- Enter the IP address of the machine that's connecting. Use the public IP shown by a site like "what is my IP" if you're at home.
- Click Add Host.
- Make sure the database user is attached to the database under MySQL Databases with the right privileges.
- Remember cPanel usernames carry a prefix, like
cpuser_dbuser. A missing prefix gives you confusing errors.
If the connection still times out, the server firewall may need your IP allowed on port 3306. Open a ticket with your IP and we'll check it.
A safer alternative: SSH tunnel
For admin work from your laptop, skip opening port 3306 entirely. Tunnel through SSH, and MySQL sees the connection as coming from localhost:
ssh -N -L 3307:127.0.0.1:3306 user@your-server-ip
Then point your client (DBeaver, TablePlus, Workbench, or the CLI) at 127.0.0.1 port 3307 with your normal @localhost credentials. No new grant, no open port.
Docker and NAT gotchas
If your app runs in a container and MySQL runs on the host, MySQL often sees the Docker bridge gateway, typically 172.17.0.1 or an address in 172.x.x.x. Read the host in the error message and grant exactly that, or use a subnet such as 'app_user'@'172.17.%'.
Prevention
- Create one user per application and limit it to the exact host that needs it.
- Grant only the privileges the app uses, never
ALL PRIVILEGES ON *.*. - Prefer private networking or SSH tunnels over public database access.
- Keep a note of which IPs have access, so you can remove old ones when a developer or server leaves.
- Test with
mysql -h your-server -u app_user -pfrom the client before changing application config.
Frequently Asked Questions
Is error 1130 a password problem?
No. MySQL rejects the connection before checking credentials, because no account matches your host. Fixing the password won't help until the host entry exists.
Why does it work from the server but not from my PC?
Because on the server you connect as localhost, which has a grant. From your PC, MySQL sees your public IP, which has none.
Do I need to restart MySQL after creating a grant?
No. CREATE USER and GRANT take effect immediately. Running FLUSH PRIVILEGES is only strictly needed if you edit the mysql.user table directly.
My home IP keeps changing. What should I do?
Use an SSH tunnel, which works regardless of your IP. Alternatively, ask your ISP for a static IP, or grant your ISP's subnet if it's stable, accepting a bit more exposure.
Is using '%' ever okay?
Only if the firewall already restricts port 3306 to trusted IPs, so the host wildcard isn't your only layer of protection. Even then, a specific host is cleaner.
