Chapter 22 · Production Capstone: Design, Secure, Scale, Tune, and Recover MySQL
Execute Failure/Recovery Drills and Defend the Final MySQL Production Design
Inject safe failures, measure detection and recovery, verify data correctness, and defend the final production design with explicit tradeoffs, unmet SLOs, rollback boundaries, and next improvements.
Learning outcomes
The capstone ends by deliberately breaking the disposable system. A design that works only in the happy path is not production-ready. Each drill has four measurements: detection, response, recovery time, and data correctness. The final deliverable is a design defense that states what met its SLO, what did not, what complexity the architecture introduces, and what would be improved next.
Inject safe blocked-connection, deadlock, load-spike, accidental-data-change, and optional node-loss failures in disposable infrastructure.
Capture MySQL/Performance Schema/log evidence that distinguishes the symptom from its mechanism.
Measure recovery time and verify business invariants instead of calling a service healthy when a process merely restarted.
Identify ambiguous transaction outcomes and explain where idempotency/reconciliation prevents duplicate business actions.
Defend the final MySQL design with explicit cost, complexity, unmet SLOs, upgrade/recovery paths, and revisit triggers.
Use one drill record for every failure
Drill ID / timestamp: _____________________________Failure injected: _________________________________Expected detector: ________________________________Detected at: ______________________________________Operator/application action: ______________________Recovery declared at: _____________________________Measured detection time: __________________________Measured recovery time: ___________________________RPO / lost-or-ambiguous operations: _______________Business invariants checked: ______________________MySQL/Router/log evidence: ________________________SLO met? yes/no/unknown: __________________________What made recovery harder: ________________________Follow-up owner and change: _______________________Do not backfill times from memory after the drill. Timestamp each phase as it happens. Unknown is an acceptable result; invented precision is not.
Drill 1: blocked connection / secure transport failure
The easiest failure to debug badly is a connection failure. Operators often restart MySQL before distinguishing wrong host, TLS verification, account host matching, lockout, firewall, Router endpoint, or server availability. The capstone starts with evidence.
# Expected failure because the account requires TLS:mysql -h 127.0.0.1 -P 3306 -u sh_cap_app -p --ssl-mode=DISABLED# Positive path; for production use VERIFY_CA / VERIFY_IDENTITY with trusted CA:mysql -h 127.0.0.1 -P 3306 -u sh_cap_app -p --ssl-mode=REQUIREDSELECT USER(),CURRENT_USER(),CURRENT_ROLE(),CONNECTION_ID();SHOW SESSION STATUS LIKE 'Ssl_cipher';SHOW GRANTS FOR CURRENT_USER;SELECT PROCESSLIST_ID,PROCESSLIST_USER,PROCESSLIST_HOST,PROCESSLIST_DBFROM performance_schema.threadsWHERE PROCESSLIST_ID=CONNECTION_ID();The wrong response is “grant everything to root and retry.” The minimum repair is to fix the actual transport/account/routing condition while preserving least privilege.
Drill 2: deadlock and retry boundary
Deadlocks are expected in concurrent transactional systems. The database detects a cycle and rolls back one transaction. The application owns the transaction boundary and retries only when the operation is safe to repeat.
USE servicehub_capstone;START TRANSACTION;UPDATE work_orders SET priority=5 WHERE work_order_id=1;-- Wait here, then attempt after Session B locks row 2:UPDATE work_orders SET priority=5 WHERE work_order_id=2;USE servicehub_capstone;START TRANSACTION;UPDATE work_orders SET priority=4 WHERE work_order_id=2;-- Now attempt row 1; one transaction should become the deadlock victim.UPDATE work_orders SET priority=4 WHERE work_order_id=1;COMMIT;SHOW ENGINE INNODB STATUS;SELECT THREAD_ID,EVENT_ID,STATE,TRX_ID,ACCESS_MODE,ISOLATION_LEVELFROM performance_schema.events_transactions_current;SELECT *FROM performance_schema.data_lock_waits;Repair the workload by taking locks in a consistent order and keeping transactions short. If a deadlock still occurs, retry the whole transaction with bounded backoff. Never retry only the final statement of a transaction whose earlier statements were rolled back.
Drill 3: load spike and the retry-storm trap
A transient slowdown becomes an outage when every application instance retries immediately and increases demand. The capstone load harness can deliberately raise concurrency until latency/error signals worsen. The application should use bounded connection pools, deadlines, jittered backoff, and graceful degradation rather than unlimited parallel retries.
1. Record baseline at concurrency 8.2. Run the same workload at concurrency 32 (or the highest safe laptop value).3. Capture p95/p99, error rate, Threads_running, CPU, storage latency, statement digests.4. Do NOT raise max_connections as the first reaction.5. Restore normal concurrency and confirm latency/error rate recover.6. Record whether the bottleneck was CPU, I/O, locks, bad SQL, pool pressure, or unknown.SHOW GLOBAL STATUS WHERE Variable_name IN('Threads_connected','Threads_running','Connection_errors_max_connections', 'Aborted_clients','Aborted_connects');SELECT EVENT_NAME,COUNT_STAR, ROUND(SUM_TIMER_WAIT/1000000000000,3) AS total_secondsFROM performance_schema.events_waits_summary_global_by_event_nameORDER BY SUM_TIMER_WAIT DESCLIMIT 15;If raising concurrency reduces throughput and increases latency, the system is saturated. More queued work is not more capacity.
Drill 4: accidental data change and recovery decision
Logical damage is where HA can make things worse by rapidly propagating the mistake. Use only the disposable capstone. Record a recovery boundary, make one identifiable bad update, and choose between transaction rollback (if still open), compensating change (if semantically safe), or restore/PITR.
USE servicehub_capstone;SELECT COUNT(*) AS open_before FROM work_orders WHERE status='OPEN';SELECT NOW(6) AS incident_marker;-- Intentional lab mistake: committed logical damage.UPDATE work_orders SET status='CANCELLED' WHERE status='OPEN';COMMIT;SELECT COUNT(*) AS open_after FROM work_orders WHERE status='OPEN';SELECT COUNT(*) AS cancelled_after FROM work_orders WHERE status='CANCELLED';Do not “repair” with an opposite mass update unless the original set is exactly knowable and no legitimate cancellations occurred concurrently. The safer production approach is to restore a backup to an isolated target, replay binary logs to the correct boundary, validate business invariants, and then plan controlled cutover/reconciliation.
Optional Drill 5: member/primary loss through Router
var cluster = dba.getCluster('serviceHubCapstone')cluster.status({extended: 1})// Identify the current primary from status output.// Stop ONLY one disposable sandbox instance using the supported sandbox command,// or stop its mysqld process through your local lab method.// Then re-run:cluster.status({extended: 1})Keep an application connection loop pointed at Router's read/write endpoint. Measure failed requests, reconnect time, ambiguous transactions, new primary identity, and business invariants. A three-member sandbox should retain quorum after one member loss. If two members are lost, quorum is lost; forcing quorum is an exceptional recovery procedure and must not be used as a routine “make it writable” command.
Correctness gates after every recovery
USE servicehub_capstone;-- Every work order references a valid asset at the same site.SELECT COUNT(*) AS cross_site_mismatchesFROM work_orders wJOIN assets a ON a.asset_id=w.asset_idWHERE a.site_id<>w.site_id;-- Every event has a work order (also enforced by FK, checked explicitly here).SELECT COUNT(*) AS orphan_eventsFROM work_order_events eLEFT JOIN work_orders w ON w.work_order_id=e.work_order_idWHERE w.work_order_id IS NULL;-- No duplicate integration idempotency keys are possible because PK enforces it.SELECT COUNT(*) AS duplicate_keysFROM ( SELECT idempotency_key FROM integration_requests GROUP BY idempotency_key HAVING COUNT(*)>1) d;SELECT status,COUNT(*)FROM work_orders GROUP BY status ORDER BY status;“mysqld is running” is not a recovery criterion. Router reachability, replication state, schema version, application canaries, and business invariants all belong to the acceptance gate.
Final design defense
| Decision | Defense | Known cost / caveat |
|---|---|---|
| MySQL 8.4 LTS + InnoDB | matches relational ACID OLTP and team skill set | requires disciplined upgrades/patching and index/transaction engineering |
| single-primary 3-member InnoDB Cluster | automatic primary election with quorum safety; one member failure tolerated | three full copies; network/failure-domain design; certification/HA operational complexity |
| Router at app tier | decouples clients from primary identity | Router itself needs deployment/restart/monitoring strategy |
| tested logical backup + binlog PITR | recovers logical/operator damage independently of HA | restore time/storage/log-retention discipline; must test continuously |
| least privilege + TLS | limits blast radius and protects transport | certificate/secret rotation and account lifecycle overhead |
| workload-derived index portfolio | targets actual access paths | write/storage cost; portfolio must evolve with workload |
| Performance Schema + SLO dashboard | ties symptoms to server evidence | instrumentation retention/overhead and alert tuning |
| expand/contract migrations | supports mixed application versions and safer rollback | temporary schema/code complexity and longer change windows |
The defense must also list what remains unmet. A laptop cannot prove datacenter failure domains, production storage latency, real 120-session concurrency, or true 99.95% monthly availability. Those are production acceptance items. The course has taught the mechanism for measuring them, not fabricated evidence that they already pass.
1. ADR + SLO/workload/capacity assumptions2. schema DDL + migration ledger/checksums3. index portfolio + EXPLAIN/EXPLAIN ANALYZE evidence4. security roles/accounts/TLS/session contract5. repeatable load-test code + >=3 run artifacts + OS/MySQL evidence6. backup manifest/checksum + latest successful restore test7. PITR preflight + retention/runway evidence8. topology diagram + cluster/replication/Router evidence9. dashboard/alerts + escalation owners10. incident runbooks + completed failure-drill records11. upgrade/rollback plan + point-of-no-return authority12. unmet SLOs, cost/complexity, known risks, revisit triggers, next improvementsFinal capstone cleanup
DROP DATABASE IF EXISTS servicehub_capstone_restore;DROP DATABASE IF EXISTS servicehub_capstone;DROP USER IF EXISTS 'sh_cap_app'@'127.0.0.1';DROP ROLE IF EXISTS 'r_sh_app_rw','r_sh_app_ro','r_sh_operator';If you created sandbox Cluster/Router instances, remove them using the MySQL Shell/AdminAPI sandbox lifecycle appropriate to your environment after saving the cluster status and drill evidence. Never run capstone cleanup commands against a real database merely because names look familiar.
Course completion: what production judgment now means
Across 22 chapters, MySQL moved from a server you can query to a system you can defend: storage and MVCC, transactions and concurrency, indexes and plans, security, backup/PITR, replication and Cluster, observability, performance, large-table lifecycle, application reliability, upgrades, and specialized boundaries. The final skill is not memorizing every variable. It is forming a hypothesis, gathering evidence, choosing the smallest safe intervention, validating correctness, and preserving a recovery path.
Knowledge check
- Why is process restart not enough to declare recovery?
- How should an application handle a deadlock victim?
- Why can HA worsen accidental data damage?
- What does a laptop HA sandbox prove?
- What makes the final design defensible?
Reveal answers
- Service reachability, topology/replication state, application canaries, schema version, and business invariants must also be correct.
- Rollback is already forced for the victim; retry the complete idempotent transaction with bounded backoff, not one final statement.
- Healthy replication can propagate the bad transaction quickly; logical recovery therefore needs backups/PITR or another independent recovery path.
- Topology mechanics, routing, election/rejoin behavior and runbook practice—not production failure-domain independence or capacity.
- Traceability from measurable requirements to design choices, reproducible evidence, tested recovery/failure behavior, explicit tradeoffs, and honest unmet risks.
Authoritative references
- MySQL Community Server 8.4 Downloads
- MySQL 8.4 — InnoDB Storage Engine
- MySQL 8.4 — EXPLAIN and EXPLAIN ANALYZE
- MySQL 8.4 — Performance Schema
- MySQL 8.4 — Backup and Recovery
- MySQL 8.4 — Point-in-Time Recovery
- MySQL 8.4 — Replication
- MySQL 8.4 — Group Replication
- MySQL Shell 8.4 — InnoDB Cluster and Router sandbox
- MySQL Router 8.4
- MySQL 8.4 — Security
- MySQL 8.4 — Upgrade and downgrade guidance