Appearance
ProxySQL
A connection pool in front of a MySQL cluster: it splits reads from writes, and it keeps working when the database primary changes.
Configuration
yaml
services:
db:
package: mysql
replicas: 2
db-proxy:
package: proxysql
config:
backend: db
backend_root_password: ${MYSQL_ROOT_PASSWORD}
users:
app: ${APP_DB_PASSWORD}Your app connects to db-proxy on port 6033. Reads go to the replicas, writes to the primary.
Surviving a database failover
ProxySQL watches each database server and routes writes to whichever one is currently accepting them. When you run managed service db promote, the promoted server starts accepting writes and ProxySQL moves traffic there on its own — no reconfiguration, no restart, no change to your app.
That covers the database dying. It does not cover the proxy dying.
Surviving a failed proxy
One proxy in front of your database is one server that takes everything down with it. Run a pair instead, sharing one address:
yaml
db-proxy:
package: proxysql
config:
backend: db
instances: 2
virtual_ip: 10.0.2.200
users:
app: ${APP_DB_PASSWORD}Your app connects to 10.0.2.200:6033. Both servers run ProxySQL; one holds the address. If it stops answering — the process wedges, the server dies, the host freezes — the other takes the address over within a few seconds (VRRP declares the holder gone after ~3 seconds; a failing health check takes 2 checks on top of that), and connections re-establish there.
The health check that decides this asks ProxySQL a real question rather than just checking the port, so a proxy that is running but stuck fails it. It deliberately does not check whether the database is reachable: that looks the same from both proxies, and dropping the address entirely would leave your app with nowhere to connect at all.
Both proxies must be at the same provider, in the same region. A shared address lives on the provider's private network — a real shared segment where a server can answer for an address that isn't its own. managed's cross-region private network routes one address to each server instead, so an address shared over it would belong to nobody. managed checks this and says so rather than configuring something that quietly never fails over.
Before it works: allow the address at your provider
Most clouds drop packets for an address they didn't hand out, so the shared address usually has to be registered on both servers' network ports first. Look for "virtual IP", "allowed address pairs", or "anti-spoofing" in your provider's console or CLI. On OpenStack-based clouds (including OVH Public Cloud):
bash
openstack port set --allowed-address ip-address=10.0.2.200 <port-of-proxy-1>
openstack port set --allowed-address ip-address=10.0.2.200 <port-of-proxy-2>managed can't see this from inside the server. A shared address that never answers is almost always this.
Pick an address that's free on your private network and outside any DHCP range your provider hands out.
Moving your app onto it
Apps hold pooled database connections open indefinitely, so changing DNS or config moves nothing on its own — the app has to reconnect. Restart it (rolling, if you have more than one) after pointing it at the shared address. Leave the old proxy running while you do: connections drain as they're replaced.
Custom routing
setup_script runs your own ProxySQL admin SQL after managed has discovered the cluster, so you can tune weights or add query rules. It re-runs whenever the topology changes, so your routing survives scaling and failovers. Placeholders: , , , , .
Set read_write_split: false to hand routing over to your script entirely.
Commands
| Command | What it does |
|---|---|
managed service db-proxy status | Backend servers and their live status |
managed service db-proxy sync | Re-discover the database servers and update routing now |
managed service db-proxy connect | Open the ProxySQL admin console |
The backend list also refreshes on its own every 5 minutes, so scaling the database is picked up without an apply.
How it works
- The admin console (127.0.0.1:6032) is ProxySQL's live configuration — its SQL tables are the config. managed never edits
proxysql.cnf, which is only read on first boot. The console listens on loopback only and is never opened in the firewall. - Replication hostgroups are what make failover automatic: ProxySQL keeps the server that accepts writes in the writer group and the rest in the reader group, following each server's read-only flag.
- The monitor account is a least-privilege login managed creates on your database (
create_monitor_user: falseif you'd rather create it yourself). - The admin username is deliberately never one of your application logins — a ProxySQL admin user that collides with a
mysql_usersentry locks you out of the console.