Skip to content

MySQL & MariaDB Protocol Guard (mysql) ​

The MySQL Protocol Guard plugin inspects MySQL and MariaDB client/server handshake packets. It monitors the initial server greeting, transparently handles SSL client requests, and checks response packets for error 0xFF with error code 1045 (ER_ACCESS_DENIED_ERROR) to stop credential stuffing attacks in real time.


Capabilities & Threat Defense ​

Threat / Attack VectorDefense MechanismAction Taken
Credential Stuffing & Brute-ForceIntercepts Error Packet 0xFF code 1045 (ER_ACCESS_DENIED_ERROR)IP automatically banned after max_auth_failures
Connection Exhaustion (Too many connections)Enforces rate limits per minute and burst capsConnection dropped or throttled before reaching MySQL
SSL Handshake HandlingTransparently detects SSL request packetsSeamless TLS encryption forwarding

Installation ​

Install the plugin via CLI or declaratively:

# Install using short nametcp-warden plugins install mysql# Or install via Git repository URLtcp-warden plugins install https://github.com/routewarden/plugins/mysql

Configuration Reference ​

Add a MySQL guard service to tcp-warden.yaml:

services:  mysql_bastion:    listen: ":3306"    upstream: "127.0.0.1:33060"    protocol: "mysql"    rate_limit:      connections_per_minute: 60      burst: 10    max_auth_failures: 3    ban_after_failures: 3    ban_duration: "2h"    plugin_config:      max_auth_failures: 3

Configuration Options ​

FieldTypeDefaultDescription
listenstring":3306"Local proxy listen address and port.
upstreamstring"127.0.0.1:33060"Target MySQL or MariaDB server address and port.
protocolstring"mysql"Must be set to "mysql" or "mariadb".
max_auth_failuresint3Failed login attempts before the client IP is banned.
ban_durationstring"2h"Duration of the automated IP ban ("30m", "2h", "24h").

Network & Deployment Architecture ​

Because MySQL operates on an unprivileged port (3306), kernel packet redirection (nftables/iptables) is not required. Deploy RouteWarden using either direct reverse proxying or container network isolation:

Option A: Direct Reverse Proxy (Bare-Metal / VM) ​

Bind RouteWarden to :3306, with MySQL listening on loopback on an alternate port or private subnet IP:

# tcp-warden.yaml — RouteWarden binds to standard port 3306services:  mysql_bastion:    listen: ":3306"    upstream: "127.0.0.1:33060" # Or private backend "10.0.0.20:3306"    protocol: "mysql"

Option B: Docker Compose Bridge Isolation ​

In containerized environments, publish port 3306 on RouteWarden while keeping the MySQL container completely internal:

services:  routewarden:    image: ghcr.io/routewarden/tcp-warden:latest    ports:      - "3306:3306"      - "9091:9091"    volumes:      - ./tcp-warden.yaml:/etc/routewarden/tcp-warden.yaml:ro    depends_on:      - db  db:    image: mariadb:11    environment:      MYSQL_ROOT_PASSWORD: securepassword    # Do NOT publish host ports; keep internal to bridge network

Testing & Verification ​

Verify legitimate logins, simulate credential errors, and check the ban list:

# Verify legitimate login through RouteWardenmysql -h 127.0.0.1 -P 3306 -u root -p

Released under the MIT License.