If you already point Claude Code at Postgres or SQLite, you'd expect MySQL to be a one-line change. Swap the driver, change the port, done. It isn't. MySQL 8 ships a default authentication plugin that older clients can't speak, `localhost` quietly means something different than `127.0.0.1`, and TLS is negotiated by connection-string parameters that have no equivalent in the Postgres world. The result is a class of connection errors — authentication plugin cannot be loaded, SSL connection is required, Host is not allowed to connect — that every MySQL developer hits and almost no AI-assistant tutorial explains.

This is the engine-specific companion to our [step-by-step guide to connecting Claude Code to your database with DBHub](https://www.deployhq.com/blog/how-to-generate-sql-queries-with-ai-step-by-step-guide-using-claude-code-and-dbhub). That pillar covers the general setup — installing DBHub, wiring it into Claude Code as an MCP server, running read-only queries. Here we go deep on the parts of MySQL that break connections and get skipped everywhere else.

* * *

## Why MySQL specifically

The general connect an AI assistant to a database story is engine-agnostic on purpose. MySQL isn't. Three things make it its own problem:

- **Auth plugins.** MySQL 8 changed the default password mechanism. If your connector library predates that change, you get an authentication error before a single query runs — and the error text points you in the wrong direction.
- **The socket/TCP split.** On the same machine, `localhost` and `127.0.0.1` can reach MySQL by two entirely different transports. That difference decides whether your connection string even works.
- **TLS-by-parameter.** MySQL negotiates SSL through DSN parameters, and MySQL 8 servers increasingly _require_ it. Omit the parameter and the handshake fails.

None of these are Claude Code's fault — they're MySQL's wire protocol showing through. But because Claude Code reaches MySQL through a connector (DBHub), every one of them can surface as a cryptic failure at startup. If you're new to the assistant itself, our [getting-started walkthrough for Claude Code in your terminal](https://www.deployhq.com/blog/getting-started-with-claude-code-the-ai-coding-assistant-for-your-terminal) covers the basics; this guide assumes you've got that far and MySQL is refusing to cooperate.

* * *

## The MySQL DSN via DBHub

DBHub is the database MCP server that lets Claude Code talk to MySQL. It takes a single connection string (a DSN) and exposes the database to the assistant as tools. For MySQL, the DSN uses the `mysql://` scheme:

```
mysql://user:password@host:3306/database
```

Broken into parts:

- `user:password` — the MySQL account DBHub authenticates as
- `host` — hostname or IP of the MySQL server
- `3306` — the default MySQL TCP port
- `database` — the schema DBHub connects to by default

You pass it to DBHub through the `--dsn` flag (or the `DSN` environment variable), then register DBHub in your Claude Code MCP configuration exactly as the pillar describes. A minimal DBHub launch looks like:

```
dbhub --dsn "mysql://appreader:s3cret@127.0.0.1:3306/shop" --readonly
```

### The TLS parameter

MySQL 8 servers frequently require an encrypted connection. When they do, a bare DSN fails the handshake. TLS is controlled by a query parameter on the DSN:

```
mysql://user:password@host:3306/database?sslmode=required
```

If your server enforces TLS and you omit the parameter, you'll see `SSL connection is required` or a handshake error. If your server has no TLS configured (common for a purely local dev instance) and you _force_ it, you'll see the opposite failure. Match the parameter to the server's actual configuration — don't cargo-cult it on or off.

* * *

## Socket vs TCP: why `localhost` and `127.0.0.1` differ

This trips up people who assume the two are interchangeable. They aren't, and MySQL treats them differently on purpose.

On Unix-like systems, the MySQL client library has a special case: when the host is the literal string `localhost`, it connects over a **Unix domain socket** — a file like `/var/run/mysqld/mysqld.sock` or `/tmp/mysql.sock` — _not_ over the network. To force a **TCP** connection, you must use `127.0.0.1` (or an explicit IP/hostname). This is documented MySQL behavior, not a quirk of any one tool.

Why it matters for your DSN:

- A `mysql://...@localhost:3306/...` DSN can be **ignored on the port** and routed to the default socket path instead. If MySQL's socket lives somewhere non-standard, the connection fails even though `3306` is wide open.
- A `mysql://...@127.0.0.1:3306/...` DSN forces TCP, so the port actually matters — which is usually what you want when DBHub runs in a container or a different process namespace than the MySQL server.

Practical rule: **for DBHub, prefer `127.0.0.1` over `localhost`** unless you specifically want socket-based access and know the socket path. TCP behaves predictably across containers, port-forwards, and SSH tunnels; socket routing does not. If you're tunnelling to a remote MySQL box over SSH, you're forwarding a TCP port — so your DSN must use `127.0.0.1:<forwarded-port>`, and `localhost` would silently break it. (Our [SSH commands reference](https://www.deployhq.com/support/ssh-commands) covers the port-forwarding side.)

* * *

## Auth plugins: the #1 cause of connection failures

If you take one thing from this article, take this. MySQL 8.0 changed the **default authentication plugin** from `mysql_native_password` to `caching_sha2_password`. Accounts created on a modern MySQL server use SHA-256-based auth by default. A connector that doesn't implement `caching_sha2_password` — or can't complete its handshake without TLS or a public key — fails with some variant of:

```
Authentication plugin 'caching_sha2_password' cannot be loaded
```

or

```
ER_NOT_SUPPORTED_AUTH_MODE
```

This is not a wrong password. The credentials are correct; the _mechanism_ is the problem. That's why the error is so confusing — it looks like an auth failure but retyping the password never helps.

### Diagnose it

Check which plugin your account actually uses:

```
SELECT user, host, plugin
FROM mysql.user
WHERE user = 'appreader';
```

If the `plugin` column reads `caching_sha2_password` and your connection keeps failing on auth, the plugin mismatch is your culprit.

### Fix it — pick the right lever

There are two legitimate fixes, and which one you choose depends on whether the problem is the _client_ or the _transport_:

**Option A — keep `caching_sha2_password`, fix the transport.** `caching_sha2_password` needs either a TLS connection or the server's public key to send the password securely. If you're failing on a fresh, unencrypted connection, enabling TLS on the DSN (`?sslmode=required`, per above) often resolves it outright. This is the preferred path — you keep the stronger auth plugin.

**Option B — switch the account to `mysql_native_password`.** If your connector genuinely can't speak the newer plugin, alter the specific account (not the server default) to use the legacy one:

```
ALTER USER 'appreader'@'%'
  IDENTIFIED WITH mysql_native_password BY 's3cret';
FLUSH PRIVILEGES;
```

Treat Option B as a compatibility fallback, not a default. `mysql_native_password` is the older, weaker mechanism and is deprecated in current MySQL releases — reach for it only when the client can't be upgraded, and scope it to the single read-only account you're connecting with, never the whole server.

> **Want the assistant to help you write these statements?** DBHub in read-only mode can't run `ALTER USER`, but Claude Code can still draft the exact SQL for you to run in your own client. Keep our [Claude Code cheatsheet](https://www.deployhq.com/cheatsheets/claude-code) open for the prompt patterns. And if you want your own AI-to-database workflow with Git-based deployment underneath it, [see how DeployHQ's automated deployment features](https://www.deployhq.com/features) tie the pieces together.

* * *

## A read-only MySQL user, scoped to one database

Never point Claude Code at MySQL through your application user or `root`. Create a dedicated account with `SELECT` only, scoped to exactly one database, and pair it with DBHub's `--readonly` flag. Two independent guardrails: the GRANT stops writes at the server, and `--readonly` stops them at the connector.

```
CREATE USER 'appreader'@'%'
  IDENTIFIED BY 's3cret';

GRANT SELECT ON shop.*
  TO 'appreader'@'%';

FLUSH PRIVILEGES;
```

That `shop.*` scoping matters: `SELECT` is granted on the `shop` schema only, so even a compromised or confused query can't read `mysql.user`, another tenant's schema, or anything outside `shop`. Then launch DBHub with the belt-and-braces flag:

```
dbhub --dsn "mysql://appreader:s3cret@127.0.0.1:3306/shop?sslmode=required" --readonly
```

The `@'%'` host part means connect from any host. If DBHub always runs from one known machine, tighten it — replace `%` with the specific IP or subnet. Which brings us to the errors table.

* * *

## Common MySQL connection errors — and the actual fix

| Error you see | What it really means | The fix |
| --- | --- | --- |
| `Access denied for user '...'@'...'` | Right user, wrong password **or** the account has no privilege for that host pattern | Verify the password; confirm a matching `user@host` row exists (`SELECT user, host FROM mysql.user`). The `@'%'` vs `@'127.0.0.1'` distinction is often the culprit |
| `SSL connection is required` / handshake failure | Server enforces TLS; DSN has no SSL parameter | Add `?sslmode=required` to the DSN. Confirm the server actually has TLS configured before forcing it |
| `Authentication plugin 'caching_sha2_password' cannot be loaded` | Connector can't complete the MySQL 8 default auth handshake — **not** a bad password | Enable TLS on the DSN (Option A), or switch that one account to `mysql_native_password` (Option B) |
| `Host '...' is not allowed to connect to this MySQL server` | No `user@host` grant matches the connecting IP | Create/adjust the account for the correct host pattern; on remote servers check `bind-address` and firewall rules |
| Connects on `localhost`, fails on `127.0.0.1` (or vice versa) | Socket-vs-TCP routing — the two hosts use different transports | Use `127.0.0.1` to force TCP; use `localhost` only when you want the Unix socket and know its path |

Work top-down: confirm the account and host pattern first, then transport (socket vs TCP), then TLS, then the auth plugin. Most MySQL won't connect sessions are one of these five, misdiagnosed as another.

If you're still deciding whether MySQL is even the right engine for what you're building, our [comparison of SQLite, PostgreSQL, and MySQL](https://www.deployhq.com/blog/sqlite-vs-postgresql-vs-mysql-choosing-the-right-database) walks through the trade-offs before you commit to any of these connection quirks.

A companion guide goes deeper on a part this one only touches: our walkthrough of [read-only guardrails for AI database access](https://www.deployhq.com/blog/ai-database-access-read-only-guardrails-claude-code) covers locking the connection down so the assistant can never write, whichever engine you're on.

* * *

## From prototype to production: the deployment handoff

Connecting Claude Code to MySQL is a _development_ superpower — you explore schemas, draft queries, and sanity-check data in plain English. But the assistant reads your database; it doesn't ship changes to it. The moment a query turns into a schema change or a seed script, you've crossed from prototyping into deployment, and that needs its own discipline.

That's the clean handoff: use Claude Code + DBHub read-only to _understand_ MySQL, and use a real deployment pipeline to _change_ it. When a schema migration is ready, it belongs in version control and runs through a repeatable process — not pasted into a production console at 2 a.m. Our guide to [database migration strategies for zero-downtime deployments](https://www.deployhq.com/blog/database-migration-strategies-for-zero-downtime-deployments-a-step-by-step-guide) covers the expand-contract patterns that keep MySQL changes safe under live traffic.

[DeployHQ](https://www.deployhq.com) closes the loop: [build pipelines](https://www.deployhq.com/features/build-pipelines) can run your migration steps as part of an automated deployment, so the SQL Claude Code helped you draft goes out through the same tested, rollback-able path as your application code. Prototype with AI, deploy with a pipeline — and [understand how MCP servers like DBHub fit together](https://www.deployhq.com/blog/build-your-first-mcp-server-model-context-protocol-guide) if you want to build your own connectors down the line.

Ready to put a real deployment process behind your MySQL changes? [Start a free](https://www.deployhq.com/signup)[DeployHQ](https://www.deployhq.com) trial and connect your first repository.

* * *

Questions about a MySQL connection that still won't behave, or about wiring migrations into your pipeline? Email us at [support@deployhq.com](mailto:support@deployhq.com) or reach out on X at [@deployhq](https://x.com/deployhq).

