A second MySQL server can protect a transaction, serve a stale copy of it, or accept a competing version of it. Those are three different architectures. Calling all of them “write scaling” hides the failure mode that matters.

Situation

RetailCo’s order platform runs on MySQL 8.4. One source owns every checkout write. Two replicas serve order history and provide promotion candidates. Query tuning, connection pooling, read routing, and larger hardware have created headroom, but the source remains the only place that can commit an order, reservation, payment state change, or idempotency record.

The next proposal sounds simple:

Replace the topology with a three-node InnoDB Cluster. If all three nodes accept writes, write capacity should triple.

That conclusion mixes four separate mechanisms:

  • classic asynchronous replication;
  • semisynchronous replication;
  • MySQL Group Replication in single-primary mode;
  • MySQL Group Replication in multi-primary mode.

InnoDB Cluster adds another layer: MySQL Shell AdminAPI manages the cluster, Group Replication maintains the replicated group, and MySQL Router directs client connections. It is not merely another name for “three MySQL servers.” MySQL documents the complete stack in MySQL InnoDB Cluster.

RetailCo is a reference architecture, not a claimed customer deployment. Its topology and workload are design inputs. This article presents no measured transaction rate, latency, conflict rate, failover time, or data-loss result.

The starting topology is conventional:

flowchart TD
  App[order applications] --> Proxy[connection and query router]
  Proxy --> Source[MySQL source — all writes]
  Proxy --> ReplicaA[replica A — eligible reads]
  Proxy --> ReplicaB[replica B — eligible reads]
  Source --> Binlog[binary log stream]
  Binlog --> ReplicaA
  Binlog --> ReplicaB

The replicas add read capacity and promotion choices. They do not divide ownership of the order tables. The foundation article in this series calls this the single-writer ceiling.

The Problem

The architecture decision is often reduced to a misleading ladder:

asynchronous
    becomes
semisynchronous
    becomes
Group Replication
    becomes
multi-primary
    equals
more write capacity

These are not four settings on one scalability control. Each changes a different contract:

MechanismMain question it answersWhat it does not establish
Asynchronous replicationCan copies receive and apply the source’s binlog later?Another write owner or zero-RPO failover
Semisynchronous replicationDid at least the configured number of replicas acknowledge receipt before the client proceeds?Replica apply completion or more writer CPU
Group Replication single-primaryCan a quorum maintain membership, order transactions, and elect one primary?Concurrent independent write domains
Group Replication multi-primaryCan several members accept writes and certify conflicts?Linear scale for a shared dataset
ShardingCan different databases own different tenants or key ranges?Transparent cross-shard transactions

The exact language matters. Traditional MySQL replication is asynchronous by default: source and replica commits are independent. Semisynchronous replication adds a receipt acknowledgment to the source commit path, but the replica still applies later. Group Replication uses a majority protocol to agree on transaction order, while each member can still have an applier queue.

“Synchronous” is therefore too imprecise by itself. Ask three explicit questions:

  1. What must happen before the client receives commit success?
  2. Which members have received the transaction at that point?
  3. Which members have actually applied it and can serve a current read?

The core problem is not choosing the strongest-sounding replication mode. It is deciding whether RetailCo needs lower RPO, automated failover, current reads, additional write-entry points, or genuinely independent write capacity.

Separate Durability, Availability, and Write Ownership

Asynchronous replication protects copies after the commit

In classic source-to-replica replication, the source executes and commits the transaction, records it in the binary log, and streams events to replicas. Each replica receives events into a relay log and applies them independently. MySQL’s diagrams explicitly show the source and replica commits as asynchronous: source-to-replica replication.

flowchart TD
  Client[client transaction] --> Execute[execute on source]
  Execute --> Commit[commit on source]
  Commit --> Ack[success to client]
  Commit --> Send[send binlog events]
  Send --> Relay[replica relay log]
  Relay --> Apply[replica applies later]

This topology is attractive because source commits do not normally wait for replica network or apply work. The trade-off is an exposure window. A promoted replica can be missing transactions that the old source acknowledged but never transmitted or that the candidate never received.

The architecture still needs:

  • GTID-based candidate comparison;
  • fencing that prevents the old source from accepting writes;
  • a promotion rule that prioritizes correctness, not only low reported lag;
  • client routing to the new source;
  • reconciliation for uncertain transactions;
  • read-after-write routing for requests that cannot tolerate replica lag.

Adding more asynchronous replicas can add read capacity. It does not reduce write work on the source; it can add binlog-sender, network, retention, and operational work.

Replica lag is usually an applier problem, and it has a specific lever

This article’s recurring point is that a replica applies the transaction later. That gap is not fixed — it is a function of how much apply parallelism the replica is allowed. Before concluding that replicas cannot keep up with the source, verify the applier configuration, because two defaults commonly leave capacity unused:

SELECT @@replica_parallel_workers,
       @@replica_parallel_type,
       @@replica_preserve_commit_order,
       @@binlog_transaction_dependency_tracking;

binlog_transaction_dependency_tracking still defaults to COMMIT_ORDER in MySQL 8.4. In that mode a replica can only apply transactions in parallel if they committed in the same binary-log group on the source, so a source with low write concurrency produces a binlog the replica must apply almost serially — a replica falling behind a source that is not itself busy. Setting it to WRITESET lets the source record which transactions touched disjoint rows, and the replica applies those in parallel regardless of source commit grouping. It is frequently the single largest improvement available to a lagging replica, and it is a source-side setting, which surprises teams who look only at the replica.

Two cautions. WRITESET requires row-based binary logging and depends on tables having primary keys — the same requirement Group Replication imposes — so a legacy table without one silently limits parallelism. And replica_preserve_commit_order (enabled by default since 8.0.27, alongside a replica_parallel_workers default of 4) keeps replica commit order identical to the source, which is what makes the replica safe to promote and to read consistently; do not disable it to chase apply throughput.

This matters for the architecture decision because a team that mistakes an applier-configuration problem for a write-capacity ceiling can spend a sharding migration solving the wrong constraint.

Semisynchronous replication narrows one loss window

With semisynchronous replication enabled, the source waits for a configured number of replica acknowledgments. The default acknowledgment count is one. Under the default AFTER_SYNC wait point, MySQL writes and synchronizes the binary log, waits for transaction-receipt acknowledgment, commits to the source storage engine, and returns to the client: configuring semisynchronous replication.

The replica acknowledgment means the events were received and placed in its relay log. It does not mean the replica has executed and committed the transaction.

flowchart TD
  Client[client transaction] --> Source[source executes transaction]
  Source --> Binlog[source syncs binary log]
  Binlog --> Relay[replica receives relay-log events]
  Relay --> Receipt[replica acknowledges receipt]
  Receipt --> SourceCommit[source commits under AFTER_SYNC]
  SourceCommit --> ClientAck[success to client]
  Relay --> Later[replica applies independently]

This can improve the failover durability contract when the promotion process selects the acknowledged replica and fences the old source. It still does not scale writes. The same source executes every transaction, and commit latency now includes an acknowledgment path.

Two operational details are easy to miss:

  1. Semisynchronous replication is disabled by default.
  2. If acknowledgment exceeds rpl_semi_sync_source_timeout, the source can revert to asynchronous operation.

An enabled configuration variable is therefore not proof that the durability contract is active. MySQL documents Rpl_semi_sync_source_status as the operational signal and exposes acknowledged and unacknowledged transaction counters: semisynchronous replication monitoring.

SHOW GLOBAL STATUS LIKE 'Rpl_semi_sync%';
SHOW GLOBAL VARIABLES LIKE 'rpl_semi_sync%';

The variable names above are deliberate. MySQL 8.4 removed the old semisync_master/semisync_slave plugins along with every rpl_semi_sync_master_* and rpl_semi_sync_slave_* variable; the supported plugins are semisync_source and semisync_replica, with rpl_semi_sync_source_* and rpl_semi_sync_replica_* variables. A configuration file carried forward from 8.0 will not start MySQL 8.4 if it still sets the old names, and automation that greps for Rpl_semi_sync_master_status will report a healthy zero forever. RetailCo should treat the upgrade to 8.4 as a semisynchronous-replication reconfiguration, not only a version bump.

RetailCo should alert when operational status falls to zero, when unacknowledged commits increase, or when wait time consumes the checkout latency budget. Quiet fallback is a change in RPO, not merely a performance event.

Group Replication single-primary is an HA architecture

Group Replication builds on InnoDB, row-based binary logging, GTIDs, write-set conflict detection, group membership, and a Paxos-based communication engine. MySQL requires replicated tables to have a primary key or a non-null unique-key equivalent so transactions can identify conflicting rows: Group Replication requirements and plugin architecture.

Single-primary mode is the default. One member is read-write; the other members use super_read_only. A transaction is committed only after a majority has received it and agreed on its relative order. Remote members then apply transactions through their applier path: Group Replication modes and flow control.

flowchart TD
  Apps[applications] --> Router[MySQL Router]
  Router --> Primary[member A — read-write primary]
  Router --> SecondaryB[member B — secondary]
  Router --> SecondaryC[member C — secondary]
  Primary --> Order[group agrees transaction order]
  SecondaryB --> Order
  SecondaryC --> Order
  Order --> ApplyA[apply on member A]
  Order --> ApplyB[apply on member B]
  Order --> ApplyC[apply on member C]

A three-member group remains quorate after one member failure because two members still form a majority. Losing the majority blocks progress because the remaining partition cannot safely decide whether it is authoritative. MySQL warns that manually forcing membership after quorum loss is a last-resort operation that can create split brain if excluded members are still active: handling loss of quorum.

Two hard boundaries should enter the capacity plan before the design is approved, because neither is tunable away:

  • A group cannot exceed nine members. This is a protocol limit, not a configuration default. It settles the question of whether Group Replication can be scaled by adding members: it cannot be scaled far, and the ninth member is a hard stop rather than a performance knee. A fleet that needs thirty read copies needs asynchronous replicas attached to the group, not a larger group.
  • Large transactions can eject a member. group_replication_transaction_size_limit bounds the size of a transaction the group will accept, defaulting to 150 MB. Beyond it, the transaction fails; well below it, a large transaction can still cause message backlog, flow-control activation, and — if a member cannot keep up — expulsion from the group. A bulk DELETE of expired reservations that was harmless on a standalone source becomes a group-stability event.

Both boundaries argue for the same conclusion as the rest of this article: Group Replication is sized for availability, and the operations that stress it are the batch and maintenance paths rather than the checkout path.

Group Replication itself does not redirect client connections. InnoDB Cluster integrates MySQL Shell AdminAPI and MySQL Router so a failed single primary can be replaced and traffic can be routed to the new one. MySQL Shell 8.4 documents BEFORE_ON_PRIMARY_FAILOVER as the InnoDB Cluster failover-consistency default, holding new work until the elected primary applies its backlog: failover consistency.

That is valuable high availability. It is still one write execution point at a time.

Multi-primary changes admission, not data ownership

In multi-primary mode, every online member can accept transactions. Each transaction’s write set is ordered and certified against concurrent work. If two transactions conflict, one can be rolled back. Every successful transaction still becomes part of the same replicated dataset and must be applied by the group.

flowchart TD
  TenantA[tenant A request] --> MemberA[member A accepts write]
  TenantB[tenant B request] --> MemberB[member B accepts write]
  Hot[hot order request] --> MemberC[member C accepts write]
  MemberA --> Certify[group ordering and certification]
  MemberB --> Certify
  MemberC --> Certify
  Certify --> Outcome{conflict detected}
  Outcome -->|no| Replicate[apply successful transaction on every member]
  Outcome -->|yes| Rollback[rollback losing transaction]

This architecture can be useful when writes enter through several locations and conflicts are rare. It does not create three independent storage owners:

  • every member stores the full replicated dataset;
  • successful writes are propagated to every member;
  • certification remains group-wide;
  • a slow member can build certification or applier queues;
  • flow control can throttle writers when queue thresholds are exceeded;
  • hot rows create conflicts rather than parallel ownership.

MySQL’s own flow-control documentation states the boundary directly: the approach works when total group writes do not exceed the write capacity of any member. That is fundamentally different from sharding, where Cluster A never applies Cluster B’s tenant-local writes.

Multi-primary also changes the SQL risk profile. MySQL 8.4 documents limitations involving SERIALIZABLE, multi-level cascading foreign keys, concurrent DDL and DML on the same object from different members, and SELECT ... FOR UPDATE expectations because locks are local rather than group-wide: Group Replication limitations.

Auto-increment spacing prevents different members from choosing the same generated values. It does not distribute tenant ownership or remove certification: InnoDB Cluster auto-increment behavior.

In Practice

RetailCo should make two decisions separately.

Decision 1 — choose the availability contract

For the existing unsharded order database, the default recommendation is a three-member InnoDB Cluster in single-primary mode when RetailCo is prepared to operate MySQL Shell, Router, quorum, distributed recovery, and failure testing.

The recommendation is based on the documented system behavior, not a throughput claim:

  • one explicit writer avoids multi-primary conflict semantics;
  • majority ordering improves the failover contract;
  • automatic election and Router integration reduce manual routing work;
  • BEFORE_ON_PRIMARY_FAILOVER prevents the new primary from exposing an older applied state;
  • each healthy member maintains the full replicated dataset and can become a candidate after applying its backlog.

Classic asynchronous replication remains reasonable when low commit latency, operational simplicity, delayed replicas, or independent read copies matter more than quorum-coordinated automated failover. Semisynchronous replication is useful when RetailCo wants a narrower acknowledged-loss window but is not ready to adopt Group Replication.

For a managed cloud database, RetailCo should compare the provider’s documented contract rather than assume the service exposes upstream Group Replication. Ask the same questions: what is durable at acknowledgment, who elects and fences, how clients reroute, whether a reader can be stale, and what RPO/RTO the failure test actually observes.

Decision 2 — choose the write-scaling boundary

If the single-primary cluster still cannot sustain checkout writes, changing to multi-primary is not the first recommendation. RetailCo already carries tenant_id, so the stronger scale-out design is independent tenant ownership:

tenant group one   -> InnoDB Cluster A
tenant group two   -> InnoDB Cluster B
tenant group three -> InnoDB Cluster C

Within each shard, Group Replication provides HA. Across shards, ownership provides write capacity. The tenant-sharded InnoDB Cluster article develops that architecture, including routing, tenant moves, schema rollout, backup, and cross-shard transactions.

Proposed benchmark — no results yet

RetailCo should test four topologies with the same MySQL 8.4 patch, schema, storage, instance shape, and durability settings:

  1. one source plus two asynchronous replicas;
  2. one source plus two semisynchronous replicas, requiring one acknowledgment;
  3. three-member InnoDB Cluster in single-primary mode;
  4. three-member InnoDB Cluster in multi-primary mode.

Run at least four workload shapes:

WorkloadPurpose
Independent tenant insertsBest case for low-conflict multi-primary admission
Different rows within one tenantExposes secondary-index and shared-record interactions
One hot inventory or sequence rowExposes certification rollback and retry pressure
Large transactionsExposes group message, memory, queue, and expulsion risks

Capture attempted and successful TPS separately. Also capture P50/P95/P99 latency, commit latency, application retries, errors, ambiguous outcomes, semisync fallback, replica apply delay, certification conflicts, local rollbacks, certification queues, remote applier queues, and flow-control activation.

The central Group Replication query is derived from MySQL’s documented Performance Schema table:

SELECT
    MEMBER_ID,
    COUNT_CONFLICTS_DETECTED,
    COUNT_TRANSACTIONS_LOCAL_ROLLBACK,
    COUNT_TRANSACTIONS_IN_QUEUE,
    COUNT_TRANSACTIONS_REMOTE_IN_APPLIER_QUEUE
FROM performance_schema.replication_group_member_stats;

The lab must also test failure behavior:

  • kill the async source before the replicas receive the last acknowledged transaction;
  • interrupt the semisync acknowledgment path until it falls back;
  • stop the Group Replication primary and verify client retry behavior;
  • isolate one of three group members;
  • isolate two of three and verify loss of quorum blocks writes;
  • restore the excluded nodes only after proving the authoritative membership and fencing state.

Status: proposed lab—no empirical result is claimed.

Recovery is not the same as member rejoin

Group Replication distributed recovery can use a remote clone and binary-log state transfer to catch up a joining member: distributed recovery. That repairs a replica of current group state. It does not recover an order deleted by a valid transaction, because that deletion is also replicated.

RetailCo still needs:

  • scheduled full backups;
  • retained binary logs for point-in-time recovery;
  • an isolated restore procedure;
  • a method to rebuild a clean cluster from restored state;
  • tenant-level recovery or repair tooling where required;
  • measured RPO and RTO for operator error as well as server loss.

High availability keeps the current state available. Backup recovers a previous state. Neither replaces the other.

Where It Breaks

AssumptionWhat the mechanism actually guaranteesFailure if ignoredRecommendation
An async replica has every acknowledged commitReceipt and apply happen after source commitPromotion loses recent writesMeasure GTID position and test RPO
Semisync means the replica applied the transactionConfigured replicas acknowledge receiptA read from the replica is still staleRoute strict reads or wait for apply
Semisync stays active once enabledTimeout can revert the source to asyncDurability silently changes during impairmentAlert on operational status and counters
Group Replication reroutes clientsGroup membership and transaction coordination are database functionsApplications remain connected to a failed memberUse and test Router, proxy, connector, or application routing
Majority receipt means every member can serve the writeRemote applier queues can lagSecondary read returns older stateSelect and test the needed consistency level
Three primaries provide three times the write capacityAll successful writes are certified and applied group-wideCPU, network, or applier ceiling remainsBenchmark successful TPS, queues, and retries
Different tenants never conflictShared indexes, counters, metadata, and DDL can create common write setsUnexpected certification rollbackInspect write sets and remove shared hot state
A distributed FOR UPDATE lock protects all writersLocks are local to a memberCross-member transaction assumptions failRedesign ownership or use single-primary mode
Automatic failover eliminates ambiguous commitsA client can lose its connection around commitDuplicate business action after retryUse idempotency keys and outcome lookup
A healthy cluster is a backupValid mistakes replicate to every memberNo point before the error can be restoredMaintain and test PITR independently

When I would not use multi-primary Group Replication

I would not use multi-primary mode to rescue a writer that is already CPU-bound while every member stores the same tables. Adding certification, networking, and apply work does not partition that load.

I would also avoid it when the workload contains hot rows, heavy SELECT ... FOR UPDATE coordination, SERIALIZABLE transactions, cascading foreign-key structures, uncoordinated DDL, large transactions, or applications that cannot safely retry certification failures.

For RetailCo’s current database, single-primary InnoDB Cluster is the clearer HA choice. If write capacity remains the problem, shard tenants across several clusters. If the application cannot carry a stable shard key or regularly needs cross-tenant atomic transactions, retain a single ownership domain while optimizing and scaling vertically, or evaluate a distributed SQL design whose transaction contract fits the workload.

What to Do Next

  • Problem: RetailCo’s replicas improve reads and recovery options, but all order writes still consume one ownership domain.
  • Solution: Choose async, semisync, or single-primary Group Replication for the required durability and failover contract; use sharding—not multi-primary terminology—to create independent write capacity.
  • Proof: Run identical workloads across all four topologies, separate attempted from committed TPS, observe certification and applier queues, force semisync fallback, lose quorum, and restore from backup.
  • Action: Pilot a three-member single-primary InnoDB Cluster for HA, keep multi-primary as an evidence-driven exception, and design tenant-sharded clusters if the measured writer ceiling remains.

The scenario verdict is:

Good fit:
  single-primary InnoDB Cluster for self-managed MySQL HA and automated election

Poor fit:
  multi-primary as a shortcut around a saturated shared-data writer

Main advantage:
  quorum-based membership, transaction ordering, and integrated failover tooling

Main limitation:
  every successful write still belongs to and is applied by the whole group

Operational complexity:
  medium to high because Router, quorum, recovery, upgrades, and fencing must be tested

Migration complexity:
  medium for a compliant InnoDB and GTID workload, high when SQL patterns violate multi-primary limits

The practical conclusion is simple: async protects copies, semisync strengthens acknowledgment, Group Replication strengthens availability, and sharding distributes ownership. Use each mechanism for the problem it actually solves.