Connecting AI Agents to PlanetScale (MySQL)

PlanetScale is MySQL-compatible (built on Vitess), and a couple of its design choices change how you connect an AI agent to it. If you've connected an agent to plain MySQL before, most of this will feel familiar, but the constraints PlanetScale puts on you actually make the agent setup safer almost by accident.
You don't have foreign keys, and that's relevant
PlanetScale historically didn't support foreign key constraints the way single-node MySQL does, because of how Vitess shards. Whether or not your setup uses them, the practical takeaway for agents is that referential integrity may live in your application rather than the database.
Why does an agent care? Because when an agent explores an unfamiliar schema, it leans on foreign keys to understand how tables relate. Without them, it's guessing which user_id points where. That's a strong argument for writing down your relationships somewhere the agent can read them — which I'll come back to.
Use a branch for anything risky
PlanetScale's headline feature is database branching, and it's a genuinely good fit for AI agents. You get an isolated branch with its own schema, you make changes there, and you open a deploy request to merge them back.
For agents, this is the answer to "what if I want it to do something other than read?" Don't let it touch your production branch. Spin up a development branch, point the agent there, and let it experiment against a real database whose blast radius is zero. Migration testing, destructive cleanup scripts, "what happens if I run this" — all fine on a branch you'll throw away.
For day-to-day read queries against live data, you'll point at the production branch, which is where the read-only setup matters.
Create a read-only user scoped to the branch
PlanetScale manages credentials through its dashboard rather than raw CREATE USER statements in most workflows. Create a new password for the branch the agent will use, and scope its role to read-only. PlanetScale lets you pick the role when you generate the credential — choose the reader role, not the admin one.
If you're managing grants at the MySQL level instead, it's the familiar shape:
create user 'agent_readonly'@'%' identified by 'a-real-secret';
grant select on your_db.* to 'agent_readonly'@'%';
flush privileges;Either way, the agent connects with a credential that physically cannot write. That's the boundary you want. A misread prompt becomes a slow SELECT, not a lost row.
PlanetScale also enforces query timeouts and connection limits at the platform level, which means some of the "protect the database itself" work is handled for you. You still want a row cap so a wide result doesn't flood the model's context, but the runaway-query-takes-down-prod scenario is partly covered by the platform.
Give the agent the relationships you don't have in the schema
Back to the foreign-key point. Because PlanetScale may not encode relationships as constraints, the agent has less to go on when it reasons about your schema. This is where annotating your tables pays off the most. A note that says "orders.customer_id references customers.id" turns a guessing game into a known join.
That's a big part of what a layer like QueryBear adds on top of the connection: it reads the PlanetScale schema, lets you describe the relationships and column meanings that aren't expressed as constraints, caps results, and logs every query. The agent talks to it over MCP with the read-only credential behind it. You can build a thinner version yourself, but the descriptions matter more on PlanetScale than on a database where foreign keys do the explaining for you.
The short version
Use a branch for anything that isn't a plain read. Use a reader credential for live queries. Write down the relationships your schema doesn't encode. Do that and your agent answers "how many orders shipped late last week" against real PlanetScale data without you wondering what it might break, because the credential it's holding genuinely can't break anything.