·                                 ·                                                   
                                                                                                                                                                                                        
               _______                                                                                                 ·                                      _________                                 
           ____:··:·::_____                                                         ·   ______            ·                      ______                   ____·:::··:::___                          ____
         __··:::·····:·::·:__    ______                        ___________          ____:··:::_____              ________________::·:::___       ·      __:·:·:·::····:··:__                ·     __···:
       __··:·::······:·:::···____·::::·___   ·      ___________:::·:::·:··__________··:::··:·:··::·___       ____::·:·····::::····::·::·:·______________·::····:·:·::·::··::_            _________··:·::
    ___:::·:·::::·:···:::::·::·::::·:·::::__________·:·:·::·::···::···:··:········:··:·:···:·:·:·:··:·_______::·:··:··:::·:::···:··:··::····::·::·:·:···::·:···:::····:·:·:·:____     ___:::·::··:::·:::
____:::····::·:·:::::··:·:···::::···:·::··:::······:::··::·:::·:·::··::····::·:·:··:·:::·::····:::··:::::·:·:·:::::··:::::::·····:··:::·····:··::··:··:·:···::···::···:·:·:·:···:_____·:::::::···::::·::
:·:·:·:::··:··::···:·:·::·::·:::·:::·::·:···:··:::···:::··:····:··::::··:··::·::::·:::··:::·:·:::··::::·:·::·:::::··:····:···:·:::··::::·:·····:·:·::::·::::::::·:···:···:·:·:···:·:·:·::::::·:::·:::·::
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
                                             ·                                    ·            ·                        ·         ·                                                                 ·   
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
─┼──┼───┼──┼──┼──┼───┼──┼──┼───┼──┼──┼───┼──┼──┼──┼───┼──┼──┼───┼──┼──┼───┼──┼──┼──┼───┼──┼──┼───┼──┼──┼───┼──┼──┼──┼───┼──┼──┼───┼──┼──┼───┼──┼──┼──┼───┼──┼──┼───┼──┼──┼───┼──┼──┼──┼───┼──┼──┼───┼──┼
─┼───┼────┼───┼────┼───┼───┼────┼───┼────┼───┼───┼────┼───┼────┼───┼───┼────┼───┼────┼───┼───┼────┼───┼────┼───┼───┼────┼───┼────┼───┼───┼────┼───┼────┼───┼───┼────┼───┼────┼───┼───┼────┼───┼────┼───┼
/    /     /  · /     /    /     /    /     /    / ·   /    /     /    /     /  · /     /    │     \    \     \    \     \    \     \    \     \    \     \    \     \    \  ·  \·   \     \    \     \ 
─┼──────┼─────┼──────┼─────┼──────┼──────┼─────┼──────┼─────┼──────┼──────┼─────┼──────┼─────┼──────┼──────┼─────┼──────┼─────┼──────┼──────┼─────┼──────┼─────┼──────┼──────┼─────┼──────┼─────┼──────┼
 /    ·  /      /    ·  /       /      /       /       /       /      /       /       /      │       \       \      \       \      ·\       \    · \       \       \      \     · \       \      \      
─────┼────────┼────────┼────────┼────────┼───────┼────────┼────────┼────────┼────────┼───────┼────────┼────────┼────────┼────────┼───────┼────────┼────────┼────────┼────────┼───────┼────────┼────────┼
    /         /         /      ·  /         /         /         /         /        /         │         \         \         \   ·     \         \  ·      \ ·       \         \        \       · \ ·     
     /          /          / ·        /          /        · /·         /          /          │          \          \          \          \          \     ·    \          \          \          \       
─────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼─────────
 /            /            /      ·  ··  /   ·        /            /            /            │      ·     ·\            \            \  ·    ·    \       ·    \             \      ·     \    ·   ·   \
        /   ·         /             /             /              /             /    ·        │  ·        ·  \       ··    \     ·       \              \         ·   \           · \             \··    
 /              /               /             ·/               /              /              │               \              \               \              \              \               \           · 
fig. field · seed = hash("how-to-use-planetscale-with-relay")200 × 24 characters
Guides

How to use PlanetScale with Relay

Put a PlanetScale branch behind Relay: one connection per branch, TLS on, masking and audit at the wire, and a local port for people and agents.

Published
Updated
Reading time
4 min
  • planetscale
  • mysql
  • relay cli
  • masking
Short answer49 words

Create a branch password in PlanetScale, register it once with relay connections create, and open it with relay connect. People and agents then use a local port. Relay keeps the PlanetScale password, connects over TLS, masks sensitive columns and records every statement against the person who opened the session.

PlanetScale gives every branch its own credentials, and that maps cleanly onto Relay: one Relay connection per branch, each with the narrowest PlanetScale role that does the job. This guide sets up a read-only connection to main and a read/write connection to a development branch, then turns on masking and checks the audit log.

What do I need before I start?

  • A PlanetScale database with at least one branch. The examples use a database called my-app with branches main and dev.
  • The Relay CLI, signed in to your workspace:
brew install relay-sh/tap/relay
relay login
relay whoami

On Linux without Homebrew, curl -fsSL https://docs.userelay.sh/install.sh | bash installs the same binary and checks its SHA-256 against the release checksums. On Windows, use choco install relay.

Which PlanetScale password should Relay hold?

Create a password per branch, with the smallest role it needs. A production branch that people and agents only read gets a reader password. A development branch where an agent may write gets a read/write one.

In the PlanetScale dashboard, open the database, choose Connect, pick the branch and create a password. Or, with the pscale CLI:

pscale password create my-app main relay-main --role reader
pscale password create my-app dev  relay-dev  --role readwriter

PlanetScale shows the username and password once. Keep the page open for the next step and copy the host it shows (for example aws.connect.psdb.cloud).

How do I register the branch as a Relay connection?

Read the password into a shell variable first, so it stays out of your shell history:

read -rs PS_PASSWORD   # paste the PlanetScale password, then Enter

relay connections create \
  --name ps-main \
  --engine mysql \
  --host aws.connect.psdb.cloud:3306 \
  --user <username from PlanetScale> \
  --password "$PS_PASSWORD" \
  --database my-app

unset PS_PASSWORD

Repeat with --name ps-dev and the dev password. A few details matter here:

  1. TLS is already on. PlanetScale only accepts encrypted connections, and relay connections create uses TLS to the database by default, verified against the system roots. There is nothing to add.
  2. The password is stored encrypted and never returned by the API. relay connections list -o wide shows stored in the CREDENTIAL column, not the value.
  3. If your secrets live in Vault, point the connection at them instead of storing a copy: relay connections update ps-main --credential-source prod-vault --credential-ref 'secret/data/planetscale#password'.

Grant the connection to the people who need it, by user or by team:

relay grants create --grantee-type team --grantee engineering \
  --target-type connection --target ps-main

How do I mask sensitive columns?

Masking runs in the Relay Agent, before rows leave the proxy, so neither the client nor the agent needs to change. Turn redaction on, then let automatic detection catch values with a strong signature (payment cards, e-mail addresses, IBANs) and add explicit rules where you know the columns:

relay connections update ps-main --redact-enabled
relay connections masking set ps-main --auto-mode best_effort

relay connections masking rules add ps-main --table users --column email \
  --strategy partial --partial-show 3
relay connections masking rules add ps-main --table payments --column card_number \
  --strategy redact
relay connections masking rules list ps-main

The strategies are redact, hash and partial. Use hash when someone needs to join or group on a value without seeing it. Explicit rules always win over automatic detection, and --exempt keeps a column out of both.

How do I connect?

relay connect ps-main

The CLI starts a local proxy and prints how to reach it:

  ps-main (mysql)
  Listening:  127.0.0.1:3306
  ...
  Connect with:
    mysql -h 127.0.0.1 -P 3306 --password=noop
  The credentials shown are placeholders the proxy ignores.

Port 3306 is the engine default. If it is busy, relay connect tries the next ports up and tells you which one it used; --port pins one. Any MySQL client, ORM or agent that can reach 127.0.0.1 now works against PlanetScale without ever holding its password. Ctrl+C closes the session.

Where do schema changes go?

Keep them in PlanetScale. With safe migrations on, PlanetScale rejects direct DDL on the production branch and routes it through a deploy request. That pairs well with the setup above: agents and people read main through ps-main, and write and migrate on dev through ps-dev, where a deploy request carries the change to production.

How do I see what ran?

Every statement through the proxy is recorded against the person who opened the session:

relay audit-logs --connection ps-main --limit 20
relay status

Add --format json to either command for jq.

Questions

Does this work with PlanetScale Postgres?

Yes. Create the connection with --engine postgres and the host, user and password from the PlanetScale Connect page. The rest of this guide is the same, and relay connect prints a psql command instead of a mysql one.

Does the PlanetScale password ever reach my laptop or the agent?

No. A stored password is encrypted at rest and never returned by the Relay API, not even to the person who set it. Only the Relay Agent uses it, on the upstream side. Your client gets placeholder credentials that the proxy ignores.

Do I need the pscale CLI?

No. The PlanetScale dashboard creates passwords too. The pscale CLI is only a faster way to do it from a terminal.

Relay Engineering

Writes about access, guardrails, masking and the Relay Agent. All posts →