Load Balancing in MySQL: Read and Write Traffic Optimization Using MySQL Router
Why Does a Database Setup Need a Load Balancer?
In a real-world application, it's common to have multiple MySQL servers — like one for writes (primary) and several for reads (replicas). But your application usually connects to just one database endpoint.
Without a load balancer, your app has no idea where to send queries — everything goes to the same server, even if others are available. This can lead to:
A load balancer solves this problem by sitting between your application and the database servers. It knows which server is healthy, which handles reads or writes, and routes queries accordingly — all without changes in your app code.
That’s exactly what MySQL Router does.
This blog explores how MySQL Router works under the hood, dives into advanced routing strategies, and shows you how to monitor and fine-tune your setup to keep your MySQL infrastructure fast, resilient, and always available.
Load Balancing options in MySQL:
In MySQL, load balancing is essential for distributing database traffic efficiently across multiple servers to improve performance, availability, and scalability. Here are the key load balancing options in MySQL:
What is MySQL Router ?
MySQL Router is a lightweight, transparent proxy designed to route database traffic between your application and a MySQL backend cluster. It acts as an intelligent middleman that directs queries to the appropriate MySQL server based on the role of each server (e.g., primary or replica) and the type of query (read or write). It’s designed for:
Router Architecture:
Sample setup:
MySQL Replica-set
Component | IP | Role | Port |
|---|---|---|---|
MySQL Primary | 127.0.0.1 | Read/Write | 3313 |
MySQL Replica 1 | 127.0.0.1 | Read-Only | 3306 |
MySQL Replica 2 | 127.0.0.1 | Read-Only | 3000 |
MySQL Router Configuration
[logger]
level = INFO
[DEFAULT]
logging_folder=/var/log/mysqlrouter
[http_server]
port=8081
bind_address=127.0.0.1
[routing:primary_write]
bind_address = 0.0.0.0
bind_port = 6446
mode = read-write
destinations = 127.0.0.1:3313
routing_strategy = first-available
[routing:replica_read]
bind_address = 127.0.0.1
bind_port = 6447
mode = read-only
destinations = 127.0.0.1:3306, 127.0.0.1:3000
routing_strategy = round-robinRouting Methods:
MySQL Router supports several routing modes for different use cases:
Types of Routing Strategies:
MySQL Router supports several routing strategies under the routing_strategy configuration option. These define how MySQL Router chooses a backend server (MySQL instance) from a list of candidates when forwarding client connections.
Essential Methods to Monitor MySQL Router:
MySQL Router can be monitored using several methods: log files, Prometheus metrics, REST API, custom scripts, and integration with monitoring tools.
Among these, logging and the REST API are key—logs help track errors and connections, while the REST API provides real-time router status and detailed statistics for effective monitoring.
Logging Options in MySQL Router
MySQL Router logging is essential for tracking its behavior, system events, and troubleshooting issues. You can configure the level of detail you want in the logs to suit your operational needs.
Log Levels:
MySQL Router REST API: Setup, Usage, and Monitoring
MySQL Router’s REST API offers a simple and effective way to monitor and manage routing within MySQL replica sets. It allows you to easily check the router’s status, view configured routes, and track important metrics to ensure smooth and reliable database traffic flow.
Setting Up the REST API:
[http_server]
port=8081
bind_address=127.0.0.1
[rest_router]
require_realm=somerealm
[rest_routing]
require_realm=somerealm
[rest_metadata_cache]
require_realm=somerealm
[http_auth_realm:somerealm]
backend=somebackend
method=basic
name=Some Realm
[http_auth_backend:somebackend]
backend=file
filename=/etc/mysqlrouter/mysqlrouter.pwdCommon REST API Endpoints:
Endpoint | Description | Plugin |
|---|---|---|
/router/status | Check Router status | rest_router |
/routes | List all routes | rest_routing |
/routes/{routeName}/blockedHosts | Get blocked IP addresses | rest_routing |
/routes/{routeName}/config | Get route configuration | rest_routing |
/routes/{routeName}/connections | Get active connections | rest_routing |
/routes/{routeName}/destinations | Get route destinations | rest_routing |
/routes/{routeName}/health | Check route health | rest_routing |
/routes/{routeName}/status | Get route status | rest_routing |
Sample Commands:
To check the route status:
[sunil@centos7 ~]$ curl -u sunil:sunil http://127.0.0.1:8081/api/20190715/routes/primary_write/status | jq
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 62 100 62 0 0 156k 0 --:--:-- --:--:-- --:--:-- 62000
{
"activeConnections": 1,
"totalConnections": 17,
"blockedHosts": 0
}To check the Route Configs:
[root@centos7 sunil]# curl -u sunil:sunil http://127.0.0.1:8081/api/20190715/routes/primary_write/config | jq
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 235 100 235 0 0 506k 0 --:--:-- --:--:-- --:--:-- 229k
{
"bindAddress": "0.0.0.0",
"bindPort": 6446,
"clientConnectTimeoutInMs": 9000,
"destinationConnectTimeoutInMs": 5000,
"maxActiveConnections": 0,
"maxConnectErrors": 100,
"protocol": "classic",
"routingStrategy": "first-available",
"mode": "read-write"
}To check the Connection details:
[root@centos7 sunil]# curl -u sunil:sunil http://127.0.0.1:8081/api/20190715/routes/primary_write/connections | jq
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 339 100 339 0 0 436k 0 --:--:-- --:--:-- --:--:-- 331k
{
"items": [
{
"bytesFromServer": 11421,
"bytesToServer": 877,
"sourceAddress": "127.0.0.1:52532",
"destinationAddress": "127.0.0.1:3313",
"timeStarted": "2025-06-04T12:00:37.137264Z",
"timeConnectedToServer": "2025-06-04T12:00:37.147759Z",
"timeLastSentToServer": "2025-06-04T12:01:02.614366Z",
"timeLastReceivedFromServer": "2025-06-04T12:01:02.614797Z"
}
]
}Conclusion:
If you're building a high-performance MySQL environment, MySQL Router isn't optional—it's essential. With built-in load balancing, flexible routing, and seamless failover capabilities, it turns your MySQL backend into a self-healing, highly available system.
Miru IT Park, Vallankumaranvillai,
Nagercoil, Tamilnadu - 629 002.
Unit 303, Vanguard Rise,
5th Main, Konena Agrahara,
Old Airport Road, Bangalore - 560 017.
Call: +91 6383016411
Email: sales@mafiree.com