Connect Claude Code to MySQL: Auth Plugins, Sockets & the Gotchas Nobody Documents

AI, PHP, and Tutorials

Connect Claude Code to MySQL: Auth Plugins, Sockets & the Gotchas Nobody Documents

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. 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 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 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 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 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 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 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 covers the expand-contract patterns that keep MySQL changes safe under live traffic.

DeployHQ closes the loop: 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 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 DeployHQ 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 or reach out on X at @deployhq.