Managed MySQL
Understand InnoDB Cluster, MySQL Router, verified TLS, resource reservations and locked logical recovery.
This guide covers private managed MySQL 8.4 in self-hosted alpha.50. Hakopod uses an installed, pinned MySQL controller; upgrading the Hakopod binary alone does not install it. Match the source and runtime images to the release's acceptance record. Development tests do not measure production capacity or physical zone independence. See the architecture, routing, security and recovery guides for shared behavior.
Choose a layout#
MySQL 8.4 uses Oracle's MySQL Operator, InnoDB Cluster and MySQL Router. Standalone has one voting database member and one Router; it cannot survive loss of its database member. Cluster mode has one primary and two, four or six voting replicas, plus two Routers. A majority of voting members must remain connected for writes. Routers do not vote and do not hold application data.
schema_version = 1
name = "orders-mysql"
engine = "mysql"
version = "8.4"
mode = "cluster"
replicas = 2
shards = 1
cpu = "500m"
memory = "1Gi"
storage_gib = 10
[tls]
mode = "required"
[placement]
spread = "nodes"
This example requires three eligible amd64 nodes. spread = "zones" instead
requires three distinct reported zones. Nodes may belong to different providers
inside one connected Kubernetes cluster. Labels do not prove physical failure
independence, sufficient network performance or resilient storage. Independent
Kubernetes clusters cannot form one managed database through this API.
Create through the guided dashboard or the shared API/CLI:
hakopod database create --project demo --environment development --file mysql.toml
hakopod database show DATABASE_ID
Each database member needs at least 500m CPU and 1Gi memory. Its sidecar adds 100m CPU and 256Mi memory. Each Router adds 100m CPU and 128Mi memory. At the minimum size, three members and two Routers request 2 CPU cores and 4Gi memory, plus three persistent volumes. Admission also reserves replacement, sandbox and recovery headroom. These allocations are distinct from measured usage.
Per-member CPU, memory, storage, placement and engine version are fixed at creation. Recover into a separate database to change them. The selected native operator does not safely reconcile arbitrary pod-resource edits. A supported replica-count change requires a current healthy observation and a reviewed revision. Capacity must remain available during the change.
Reducing replicas does not release the earlier CPU or storage reservation.
Both remain reserved until the database is deleted and its owned volumes are
reclaimed. After a healthy reduction, the operator may report
ONLINE_PARTIAL even when the requested members are online. Hakopod accepts
that state only after its own checks find the exact requested set of owned,
ready pods, one primary, online native membership and the required transport
policy on every member. Memory reservations follow the completed layout.
Retry a failed replica change#
Open the database's Activity tab and select Review retry on the latest failed replica change. The review checks whether the controller accepted the requested revision. If it did, Hakopod checks that rollout again. If it did not, the previous layout must pass fresh health and topology checks before the change can be retried.
Review the warnings and type the database name to confirm. The retry creates a separate operation at the same configuration revision and preserves the earlier failure, requested replica count and reservations. It cannot bypass lost quorum or choose a different count. The database stays unready until its native checks pass.
The API, CLI and SDK use the same review. If the connection fails, resend the exact request and idempotency key to retrieve that attempt. If the attempt itself fails, review the latest failure and use a new key. See the CLI retry commands.
Connect with verified TLS#
The application database and account are both named app. The account owns
app.*, requires TLS and permits at most 100 connections. It cannot create
global accounts or administer the server. Administrative bootstrap credentials
remain in a separate owned Secret and are never bound to applications.
Use the observed write endpoint on port 6446 for writes and primary reads. A cluster also exposes a replica endpoint on port 6447. These are explicit route choices; the Router does not parse arbitrary SQL and choose a destination for each statement. Existing sessions must reconnect after failover. Applications must handle aborted transactions and retry only when safe. Replica routing is not a separate database permission role and does not guarantee read-after-write consistency.
Download the public CA from Connections & security, or obtain its
certificate_pem through hakopod database trust DATABASE_ID. Native clients
must verify both the issuer and endpoint hostname:
mysql --host=OBSERVED_HOST --port=6446 --user=app --password \
--database=app --ssl-mode=VERIFY_IDENTITY --ssl-ca=database-ca.crt
Application bindings use protocol mysql and an explicit read_write or
read_only endpoint. They mount the public CA at the path shown in the
connection instructions. Configure your driver's TLS options with that CA and
hostname verification; a generic MySQL URL does not configure every driver.
Do not disable certificate verification to work around a connection failure.
The security view reports verification only after native connections succeed, plaintext is rejected and the served certificate matches the issued identity. Renewal keeps an overlap trust chain for existing clients and reloads MySQL and Router certificates. Application trust renewal rolls out the binding's public CA. Stale or incomplete checks remain unverified in the dashboard.
Private and public access#
Alpha.50 provides private MySQL routes inside the authorized application network. It does not publish a database listener to the Internet. Public MySQL endpoint descriptors remain disabled, and Cloud does not offer public database endpoints. A private Router address still requires CA and hostname verification.
Monitor and recover#
Member resource samples include the MySQL server and its sidecar. Separate Router resources are not included in those charts. The member limit displays the server and sidecar allocations separately.
Native activity statistics describe the observed primary. Connection counts
cover the app account; data size estimates application table and index bytes.
The Server queries counter is server-wide and includes administrative queries.
Filesystem usage, query latency, replication lag and cache-hit ratio are not
collected for MySQL. Missing statistics remain unavailable.
Managed backups capture application tables, binary values, views, routines, events and triggers into an encrypted, verified logical archive. Capture holds a global read lock: writes and DDL wait while the bounded dump runs. This is not an online backup or point-in-time recovery. Topology changes invalidate capture.
Recovery requires a verified MySQL 8.4 archive and a separate empty MySQL 8.4 target. Application access is isolated during restore; existing app sessions are disconnected and the target is checked again for emptiness. Archive SQL runs as the application account, without global privileges. The source is retained. Application ingress remains closed until durable recovery completion and inspection; maintenance reconciliation then restores the private network grant. Inspect recovered data before connecting an application, and account for writes after the capture point. External MySQL archive import is not yet supported by the import API.
Deletion first asks the MySQL controller to remove its database object while pods and credentials are still present. Namespace removal follows controller finalization. The durable allocation remains reserved until persistent volumes are reclaimed. An interrupted or stalled deletion must remain visible as such.
Operator prerequisites#
The implementation pins MySQL Operator 26.7.0-2.3.0, server 8.4.12 and Router
8.4.10 by digest. The verified manifests currently require amd64. The release
installer carries the controller as a static mysql.json payload and rejects a
missing or unexpected controller file. On the target host, first create a
reviewable controller plan with installer/modules.py managed-databases --plan.
Check its cluster identity, resource identities, images, placement and resource
limits, then apply that same plan within its validity window with
--apply-reviewed-plan. The installer uses the packaged JSON and does not
download a chart on the target host.
The controller installation guide lists the complete plan and apply commands.
Installing the controller is one admission requirement. Creation also checks the pinned controller version, healthy rollout, permissions, placement and capacity. The development installer remains limited to the named Hakopod development cluster.
On gVisor workers, MySQL and its sidecar share a bounded 16Mi socket volume. Containerd must pass these exact pod annotations to runsc:
pod_annotations = [
"dev.gvisor.spec.mount.rundir.share",
"dev.gvisor.spec.mount.rundir.type",
"dev.gvisor.spec.mount.rundir.options",
]
Place this setting in the existing runsc runtime table appropriate to the installed containerd version. Preserve the runtime's other settings and follow the operator's node-maintenance procedure when reloading it. Without shared mount hints, a sidecar can see lock files but cannot connect to the server's Unix socket. Native readiness checks prevent that database from becoming ready. See gVisor's shared-volume configuration.
MySQL Router and managed Vitess are distinct capabilities. Enabling MySQL does not imply that Vitess is available.
Release verification#
The alpha.50 managed database acceptance record identifies the tested source, controller and runtime images, covered MySQL operations and remaining limits. Use that record instead of results from an older source revision. Private engine acceptance does not enable a public listener or Cloud public access.
Source and related guides#
The implementation is in the public Hakopod repository. In the source checkout, read docs/managed-mysql.md with its corresponding engine runtime and acceptance tests. Release source references must match the version you install. Return to the database catalog to compare availability.