A silent primary failure at 2 AM is every on-call engineer's nightmare: replication lag spikes, writes stall, and the team scrambles to manually promote a replica before SLA timers expire. MySQL Orchestrator eliminates this scenario by continuously mapping your replication topology, detecting failures within seconds, and executing a safe, automated master promotion — all without human intervention. Originally built by GitHub's infrastructure team and now part of the Percona ecosystem, Orchestrator has become the de-facto standard for MySQL high availability at scale. In this guide you will learn how to install, configure, and operate Orchestrator in production, including Raft-based HA for Orchestrator itself and integration with ProxySQL for seamless traffic rerouting.
- Orchestrator continuously discovers and visualizes your MySQL replication topology via information_schema queries.
- It detects master failure and automatically promotes the most up-to-date replica, handling relay-log application and co-primary cleanup.
- Configure
RecoverMasterClusterFiltersandPromotionRuleto control which replicas are eligible for promotion. - Run three Orchestrator nodes in Raft mode to eliminate Orchestrator itself as a single point of failure.
- Hook scripts (
OnFailoverDetection,PostMasterFailover) let you integrate with ProxySQL, DNS, or alerting pipelines automatically.
What is MySQL Orchestrator?
Orchestrator is an open-source MySQL replication topology manager written in Go. It performs three primary jobs:
- Discovery — periodically connects to every known MySQL instance, reads
SHOW SLAVE STATUSandSHOW MASTER STATUS, and builds a live graph of who replicates from whom. - Visualization — exposes that graph through a web UI and a REST API, giving operators a real-time map of lag, GTID positions, and replica counts.
- Recovery — when a master becomes unreachable, Orchestrator runs an election, promotes the best candidate, re-points all surviving replicas to the new master, and fires hook scripts to update routing layers.
Orchestrator stores its state in a backend MySQL (or SQLite) database and — crucially — supports a three-node Raft cluster so that the tool managing your MySQL HA is itself highly available.
Topology Architecture
A typical production setup looks like this:
Each Orchestrator node independently probes every MySQL instance. The Raft leader is the only node that executes recovery actions, preventing split-brain promotions. The backend state database can itself be a replicated MySQL cluster separate from the application topology being managed.
Never point Orchestrator at the same MySQL cluster it is managing as its backend store. A master failover would corrupt Orchestrator's own state at the worst possible moment.
Installation
Orchestrator ships as a single statically-linked binary. Install it on each of your three Orchestrator nodes:
# Download the latest release (adjust version as needed)
wget https://github.com/openark/orchestrator/releases/download/v3.2.6/orchestrator-3.2.6-linux-amd64.tar.gz
tar -xzf orchestrator-3.2.6-linux-amd64.tar.gz -C /usr/local/
# Create a symlink
ln -s /usr/local/orchestrator/orchestrator /usr/local/bin/orchestrator
ln -s /usr/local/orchestrator/orchestrator-client /usr/local/bin/orchestrator-client
# Create directories
mkdir -p /etc/orchestrator /var/log/orchestrator /var/lib/orchestratorNext, create the topology user on every MySQL instance Orchestrator will manage. This user must exist on master and all replicas:
-- Run on each MySQL instance
CREATE USER 'orchestrator'@'%' IDENTIFIED BY 'str0ng_orch_pass';
GRANT SUPER, PROCESS, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'orchestrator'@'%';
GRANT SELECT ON mysql.slave_master_info TO 'orchestrator'@'%';
GRANT SELECT ON performance_schema.replication_group_members TO 'orchestrator'@'%';
FLUSH PRIVILEGES;If you are using MySQL 8.0, replace SUPER with the fine-grained privileges SYSTEM_VARIABLES_ADMIN, SESSION_VARIABLES_ADMIN, and BINLOG_ADMIN to follow the principle of least privilege.
Configuration
Orchestrator is configured through a single JSON file. Below is a production-ready /etc/orchestrator/orchestrator.conf.json that covers topology credentials, recovery policies, Raft clustering, and ProxySQL integration hooks.
{
"Debug": false,
"EnableSyslog": false,
"ListenAddress": ":3000",
"MySQLTopologyUser": "orchestrator",
"MySQLTopologyPassword": "str0ng_orch_pass",
"MySQLTopologyCredentialsConfigFile": "",
"MySQLOrchestratorHost": "orch-backend.internal",
"MySQLOrchestratorPort": 3306,
"MySQLOrchestratorDatabase": "orchestrator",
"MySQLOrchestratorUser": "orch_rw",
"MySQLOrchestratorPassword": "backend_pass",
"SlaveLagQuery": "",
"SlaveStartPostWaitMilliseconds": 1000,
"DiscoverByShowSlaveHosts": true,
"RecoverMasterClusterFilters": ["*"],
"RecoverIntermediateMasterClusterFilters": ["*"],
"RecoveryPeriodBlockMinutes": 30,
"RecoveryIgnoreHostnameFilters": [],
"FailMasterPromotionIfSQLThreadNotUpToDate": true,
"DelayMasterPromotionIfSQLThreadNotUpToDate": true,
"PromotionIgnoreHostnameFilters": [],
"DetachLostReplicasAfterMasterFailover": true,
"ApplyMySQLPromotionAfterMasterFailover": true,
"MasterFailoverDetachReplicaMasterHost": true,
"PostponeReplicaRecoveryOnLagMinutes": 0,
"OnFailoverDetectionProcesses": [
"/etc/orchestrator/hooks/on_failover_detection.sh {failureType} {failedHost} {failedPort} {successorHost} {successorPort}"
],
"PostMasterFailoverProcesses": [
"/etc/orchestrator/hooks/post_master_failover.sh {failureType} {failedHost} {failedPort} {successorHost} {successorPort} {lostReplicas}"
],
"PostFailoverProcesses": [],
"PreGracefulTakeoverProcesses": [],
"RaftEnabled": true,
"RaftDataDir": "/var/lib/orchestrator",
"RaftBind": "0.0.0.0",
"DefaultRaftPort": 10008,
"RaftNodes": [
"orch-1.internal",
"orch-2.internal",
"orch-3.internal"
],
"AuthenticationMethod": "token",
"HTTPAuthUser": "",
"HTTPAuthPassword": "",
"HostnameResolveMethod": "default",
"MySQLHostnameResolveMethod": "@@hostname",
"UnseenInstanceForgetHours": 240,
"DiscoveryMaxConcurrency": 300,
"InstancePollSeconds": 5
}The most important settings to understand:
MySQLTopologyUser— the credential Orchestrator uses to probe every managed MySQL instance. It must exist on all nodes with the grants shown in the installation section.RecoverMasterClusterFilters— a list of cluster name patterns for which automated master recovery is enabled.["*"]enables it for all clusters; use["prod-cluster", "analytics-cluster"]to be selective.FailMasterPromotionIfSQLThreadNotUpToDate— blocks promotion of a replica whose SQL thread has not fully applied its relay log. Combined withDelayMasterPromotionIfSQLThreadNotUpToDate: true, Orchestrator will wait for the SQL thread to catch up rather than promoting a lagging replica.RaftEnabled/RaftNodes— activates the three-node consensus mode. The Raft leader is the sole node authorized to issue recovery commands, preventing simultaneous conflicting promotions.
Setting PromotionRule on Replicas
Not all replicas are equal candidates for promotion. Tag each replica with its preferred role using the Orchestrator API or CLI:
# Mark replica-1 as the preferred promotion candidate
orchestrator-client -c set-candidate-promotion-rule \
-i replica-1.internal:3306 \
--promotion-rule=prefer
# Mark replica-2 as acceptable but not preferred
orchestrator-client -c set-candidate-promotion-rule \
-i replica-2.internal:3306 \
--promotion-rule=neutral
# Mark replica-3 (cross-datacenter) as never eligible for promotion
orchestrator-client -c set-candidate-promotion-rule \
-i replica-3.internal:3306 \
--promotion-rule=must_notValid PromotionRule values are prefer, neutral, prefer_not, and must_not. Orchestrator scores candidates by combining this rule with GTID execution position, replication lag, and slave count.
Automated Failover Walkthrough
When Orchestrator cannot reach a master after consecutive failed probes (controlled by InstancePollSeconds and internal dead-master thresholds), it initiates the following sequence:
- Dead master detection — multiple Raft nodes independently confirm the master is unreachable to avoid false positives from network partitions.
- Candidate election — Orchestrator ranks surviving replicas by
PromotionRule, GTID errant transactions, replication lag, and replica count beneath them. - Relay log draining — if
DelayMasterPromotionIfSQLThreadNotUpToDateis true, Orchestrator waits for the winning candidate's SQL thread to fully apply its relay log. - Promotion —
STOP SLAVE; RESET SLAVE ALL;on the new master, followed bySET GLOBAL read_only=OFF. - Re-pointing replicas — all surviving replicas receive
CHANGE MASTER TO MASTER_HOST='new-master', MASTER_AUTO_POSITION=1;. - Hook execution —
PostMasterFailoverProcessesscripts fire with topology metadata injected as environment variables.
If your replicas use non-GTID replication (binlog_format=STATEMENT with file+position coordinates), Orchestrator can still perform failover but the re-pointing step is more fragile. Migrate to GTID mode (gtid_mode=ON, enforce_gtid_consistency=ON) before relying on automated recovery in production.
ProxySQL Integration via Hook Scripts
The PostMasterFailover hook is where you update ProxySQL's writer hostgroup to point at the new master. A minimal hook script:
#!/usr/bin/env bash
# /etc/orchestrator/hooks/post_master_failover.sh
FAILURE_TYPE="$1"
FAILED_HOST="$2"
FAILED_PORT="$3"
NEW_MASTER_HOST="$4"
NEW_MASTER_PORT="$5"
PROXYSQL_HOST="proxysql.internal"
PROXYSQL_ADMIN_PORT="6032"
PROXYSQL_USER="radmin"
PROXYSQL_PASS="radmin_pass"
mysql -h"${PROXYSQL_HOST}" -P"${PROXYSQL_ADMIN_PORT}" \
-u"${PROXYSQL_USER}" -p"${PROXYSQL_PASS}" <Make the script executable: chmod +x /etc/orchestrator/hooks/post_master_failover.sh. Orchestrator passes all placeholder values from the config (e.g., {successorHost}) as positional arguments in the order they appear in PostMasterFailoverProcesses.
orchestrator-client CLI Reference
The orchestrator-client binary communicates with the Orchestrator HTTP API, making it easy to script topology operations from CI/CD pipelines or maintenance runbooks.
# Seed discovery — tell Orchestrator about a new instance
orchestrator-client -c discover -i master.internal:3306
# Print current topology for a cluster
orchestrator-client -c topology -i master.internal:3306
# Manually initiate a graceful master takeover (planned switchover)
orchestrator-client -c graceful-master-takeover -i master.internal:3306
# Force a specific replica to become master (break-glass)
orchestrator-client -c force-master-failover -i master.internal:3306
# Relocate a replica under a different parent
orchestrator-client -c relocate \
-i replica-3.internal:3306 \
--sibling replica-1.internal:3306
# List all clusters known to Orchestrator
orchestrator-client -c clusters
# Show current recovery history
orchestrator-client -c recovery-info
# Acknowledge (suppress) a recovery to stop repeated alerting
orchestrator-client -c ack-recovery -i master.internal:3306 --comment "investigated"Set the environment variable ORCHESTRATOR_API to http://orch-1.internal:3000/api (or the VIP in front of your Raft cluster) so you do not need to pass -api on every command. In Raft mode, non-leader nodes automatically proxy write requests to the current leader.
Common Pitfalls
- Stale topology after hostname changes — if you rename a replica host, Orchestrator may hold a ghost entry. Run
orchestrator-client -c forget -i old-hostname:3306to purge it. - Recovery blocked by
RecoveryPeriodBlockMinutes— after a recovery, Orchestrator blocks additional recoveries on that cluster for the configured window (default 30 minutes). If you need to re-run a recovery immediately in a drill, acknowledge the previous recovery first withack-recovery. - Errant transactions causing promotion block — a replica with errant GTIDs (transactions not in the master's binary log) will be deprioritized or skipped. Identify them with
SHOW GLOBAL VARIABLES LIKE 'gtid_executed'andgtid_subtract(), then fix withBINLOG_GTID_RECOVERYor injecting empty transactions. - Hook script timeouts — if
PostMasterFailoverProcessesscripts take longer than 30 seconds, Orchestrator logs a warning but does not block. Keep hooks idempotent and fast; offload slow work to a background queue. - Raft split-brain during network partition — with three Raft nodes, any two nodes form a quorum. If all three nodes are in the same datacenter and that datacenter loses network connectivity, Orchestrator becomes read-only but will not cause a split-brain promotion. Spread Raft nodes across availability zones.
Do not run Orchestrator in non-Raft mode (RaftEnabled: false) with multiple Orchestrator instances sharing the same backend database. Without Raft coordination, two Orchestrator nodes can simultaneously detect a dead master and execute competing promotions, resulting in a split-brain cluster.
Key Takeaways
- Orchestrator provides topology-aware automated failover, eliminating the need for manual master promotion during outages and dramatically reducing MTTR.
- Enable GTID replication on all managed instances before relying on automated recovery — file+position failover is fragile at scale.
- Use
RecoverMasterClusterFiltersto opt specific clusters into automated recovery, andPromotionRuleto declare which replicas are eligible candidates. - Deploy three Orchestrator nodes in Raft mode across different availability zones to remove Orchestrator itself as a single point of failure.
- Hook scripts (
OnFailoverDetection,PostMasterFailover) are the integration seam between Orchestrator's topology changes and your routing layer (ProxySQL, HAProxy, DNS). - Regularly test failover in a staging environment using
graceful-master-takeoverto validate your hooks, ProxySQL config, and application reconnection logic before an unplanned outage forces a real test.
Managed MySQL Without the Operational Overhead
Running Orchestrator in production requires careful configuration, ongoing tuning, and expertise across replication internals, Raft consensus, and ProxySQL routing. If you would rather focus on your application than your database infrastructure, JusDB provides fully managed MySQL with built-in high availability, automated failover, and real-time topology monitoring — no Orchestrator configuration required. Our team handles version upgrades, security patches, and failover drills so your engineers can ship product instead of managing replicas.
Talk to a JusDB engineer to see how we can simplify your MySQL operations.