|
| 1 | +--- |
| 2 | +type: "docs" |
| 3 | +title: "Configure MySQL Source" |
| 4 | +linkTitle: "MySQL" |
| 5 | +weight: 55 |
| 6 | +description: "Stream changes from MySQL using binlog replication" |
| 7 | +related: |
| 8 | + concepts: |
| 9 | + - title: "Sources" |
| 10 | + url: "/concepts/sources/" |
| 11 | + howto: |
| 12 | + - title: "Configure Bootstrap Providers" |
| 13 | + url: "/drasi-server/how-to-guides/configuration/configure-bootstrap-providers/" |
| 14 | + reference: |
| 15 | + - title: "Configuration Reference" |
| 16 | + url: "/drasi-server/reference/configuration/" |
| 17 | +--- |
| 18 | + |
| 19 | +The MySQL {{< term "Source" >}} streams row-level changes from a MySQL database using **binary log (binlog) replication**. |
| 20 | + |
| 21 | +## When to use the MySQL source |
| 22 | + |
| 23 | +- Keep Drasi queries continuously updated from a system-of-record MySQL database. |
| 24 | +- Drive reactions from database changes (alerts, notifications, downstream sync, cache/materialized-view updates). |
| 25 | +- Build reactive services that need transactional ordering of changes. |
| 26 | + |
| 27 | +## Prerequisites |
| 28 | + |
| 29 | +- MySQL **5.7+** or **8.0+**. |
| 30 | +- Binary logging enabled with row-based format: |
| 31 | + - `binlog_format = ROW` |
| 32 | + - `binlog_row_image = FULL` |
| 33 | + - `binlog_row_metadata = FULL` |
| 34 | +- A database user with **REPLICATION SLAVE**, **REPLICATION CLIENT**, and **SELECT** permissions. |
| 35 | + |
| 36 | +## How it connects |
| 37 | + |
| 38 | +This source **connects outbound** from Drasi Server to MySQL over the MySQL protocol; it does not open an inbound port. |
| 39 | + |
| 40 | +## Quick example (Drasi Server config) |
| 41 | + |
| 42 | +Drasi Server source configuration uses **camelCase** keys. |
| 43 | + |
| 44 | +```yaml |
| 45 | +sources: |
| 46 | + - kind: mysql |
| 47 | + id: orders-db |
| 48 | + autoStart: true |
| 49 | + |
| 50 | + host: ${MYSQL_HOST:-localhost} |
| 51 | + port: ${MYSQL_PORT:-3306} |
| 52 | + database: ${MYSQL_DATABASE:-mydb} |
| 53 | + user: ${MYSQL_USER:-drasi_user} |
| 54 | + password: ${MYSQL_PASSWORD} |
| 55 | + |
| 56 | + # Tables to monitor |
| 57 | + tables: |
| 58 | + - orders |
| 59 | + - customers |
| 60 | + |
| 61 | + # Optional: override key columns for tables without primary keys |
| 62 | + tableKeys: |
| 63 | + - table: order_items |
| 64 | + keyColumns: [order_id, product_id] |
| 65 | + |
| 66 | + # Optional: where to start reading the binlog |
| 67 | + startPosition: from_end |
| 68 | + |
| 69 | + # Optional: preload initial state for newly-subscribed queries |
| 70 | + bootstrapProvider: |
| 71 | + kind: mysql |
| 72 | +``` |
| 73 | +
|
| 74 | +## Configure MySQL |
| 75 | +
|
| 76 | +### 1) Enable binary logging with row format |
| 77 | +
|
| 78 | +Add to your MySQL configuration (`my.cnf` or `my.ini`) and restart MySQL: |
| 79 | + |
| 80 | +```ini |
| 81 | +[mysqld] |
| 82 | +log-bin = mysql-bin |
| 83 | +binlog_format = ROW |
| 84 | +binlog_row_image = FULL |
| 85 | +binlog_row_metadata = FULL |
| 86 | +server-id = 1 |
| 87 | +``` |
| 88 | + |
| 89 | +### 2) Create a replication user |
| 90 | + |
| 91 | +```sql |
| 92 | +CREATE USER 'drasi_user'@'%' IDENTIFIED BY 'your-password'; |
| 93 | +GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'drasi_user'@'%'; |
| 94 | +GRANT SELECT ON mydb.* TO 'drasi_user'@'%'; |
| 95 | +FLUSH PRIVILEGES; |
| 96 | +``` |
| 97 | + |
| 98 | +### 3) (Recommended) Ensure tables have primary keys |
| 99 | + |
| 100 | +For reliable change tracking, tables should have primary keys. |
| 101 | +If replicating tables without primary keys, configure `tableKeys` (below). |
| 102 | + |
| 103 | +## Data mapping |
| 104 | + |
| 105 | +- Each changed row becomes a Drasi graph {{< term "Node" >}}. |
| 106 | +- **Label**: table name (for example `orders`). |
| 107 | +- **Properties**: columns become node properties. |
| 108 | +- **Element ID**: `table:key` (for example `orders:123`). |
| 109 | + |
| 110 | +If no key columns can be resolved for a row, the source logs a warning and falls back to a generated UUID: `table:uuid`. |
| 111 | + |
| 112 | +## Configuration reference (Drasi Server) |
| 113 | + |
| 114 | +| Field | Type | Default | Description | |
| 115 | +|---|---:|---:|---| |
| 116 | +| `kind` | string | required | Must be `mysql`. | |
| 117 | +| `id` | string | required | Unique source identifier. | |
| 118 | +| `autoStart` | boolean | `true` | Whether Drasi Server starts the source on startup. | |
| 119 | +| `bootstrapProvider` | object | none | Optional bootstrap provider for initial state. For MySQL bootstrap, use `{ kind: mysql }`. | |
| 120 | +| `host` | string | `localhost` | MySQL host. | |
| 121 | +| `port` | integer | `3306` | MySQL port. | |
| 122 | +| `database` | string | required | Database name. | |
| 123 | +| `user` | string | required | Database user (must have replication permission). | |
| 124 | +| `password` | string | `""` | Password. | |
| 125 | +| `tables` | string[] | `[]` | List of tables to monitor for changes. | |
| 126 | +| `sslMode` | string | `disabled` | SSL mode: `disabled`, `if_available`, `require`, `require_verify_ca`, `require_verify_full`. | |
| 127 | +| `tableKeys` | array | `[]` | Override key columns per table (see below). | |
| 128 | +| `startPosition` | string | `from_end` | Where to start the binlog stream: `from_start`, `from_end`, `from_position`, `from_gtid`. | |
| 129 | +| `serverId` | integer | auto-generated | MySQL server ID for the replication connection. Auto-generated from source instance ID if not specified. | |
| 130 | +| `heartbeatIntervalSeconds` | integer | `30` | Heartbeat interval in seconds for the replication connection. | |
| 131 | + |
| 132 | +Fields marked with support Drasi Server config references like `${ENV_VAR}` / `${ENV_VAR:-default}`. |
| 133 | + |
| 134 | +### tableKeys |
| 135 | + |
| 136 | +Use `tableKeys` to define key columns for element ID generation when primary keys are missing or not suitable. |
| 137 | + |
| 138 | +```yaml |
| 139 | +tableKeys: |
| 140 | + - table: order_items |
| 141 | + keyColumns: [order_id, product_id] |
| 142 | +``` |
| 143 | + |
| 144 | +Notes: |
| 145 | +- Key columns are joined with `_` in the element ID (for example `order_items:1001_5`). |
| 146 | + |
| 147 | +### startPosition |
| 148 | + |
| 149 | +Controls where binlog replication begins when the source starts for the first time. |
| 150 | + |
| 151 | +| Value | Description | |
| 152 | +|---|---| |
| 153 | +| `from_end` | Start from the current end of the binlog (default). Only captures new changes. | |
| 154 | +| `from_start` | Replay the binlog from the beginning. | |
| 155 | +| `from_position` | Start from a specific binlog file and position. | |
| 156 | +| `from_gtid` | Start from a specific GTID set. | |
| 157 | + |
| 158 | +## Performance tuning notes |
| 159 | + |
| 160 | +- Only list the tables you need in `tables`; this reduces processing overhead. |
| 161 | +- The `heartbeatIntervalSeconds` prevents idle connection timeouts and allows the source to detect disconnections faster. |
| 162 | +- Monitor binlog retention to ensure the source can reconnect after brief outages. |
| 163 | + |
| 164 | +## Verifying it works |
| 165 | + |
| 166 | +After starting Drasi Server with your MySQL source, verify the connection: |
| 167 | + |
| 168 | +### 1. Check source status |
| 169 | + |
| 170 | +```bash |
| 171 | +curl http://localhost:8080/api/v1/sources/orders-db |
| 172 | +``` |
| 173 | + |
| 174 | +Expected response includes `"status": "running"`. |
| 175 | +
|
| 176 | +### 2. Make a test change in MySQL |
| 177 | +
|
| 178 | +```sql |
| 179 | +INSERT INTO orders (id, customer_id, total, status) |
| 180 | +VALUES (999, 1, 100.00, 'pending'); |
| 181 | +``` |
| 182 | + |
| 183 | +### 3. Verify the change was captured |
| 184 | + |
| 185 | +If you have a log reaction configured: |
| 186 | + |
| 187 | +``` |
| 188 | +[console-output] Query 'my-query' (1 items): |
| 189 | +[console-output] [ADD] {"id":"999","customer_id":"1","total":"100.00","status":"pending"} |
| 190 | +``` |
| 191 | + |
| 192 | +Or query results via API: |
| 193 | + |
| 194 | +```bash |
| 195 | +curl http://localhost:8080/api/v1/queries/my-query/results |
| 196 | +``` |
| 197 | + |
| 198 | +### 4. Check binlog status in MySQL |
| 199 | + |
| 200 | +```sql |
| 201 | +SHOW BINARY LOG STATUS; |
| 202 | +SHOW REPLICAS; |
| 203 | +``` |
| 204 | + |
| 205 | +## Troubleshooting |
| 206 | + |
| 207 | +| Error | Cause | Solution | |
| 208 | +|-------|-------|----------| |
| 209 | +| `binlog_format must be ROW` | Binlog format not set to ROW | Set `binlog_format = ROW` in `my.cnf` and restart | |
| 210 | +| `Access denied; you need the REPLICATION SLAVE privilege` | Missing permission | `GRANT REPLICATION SLAVE ON *.* TO 'drasi_user'@'%';` | |
| 211 | +| `Can't connect to MySQL server` | Wrong host/port | Verify `host` and `port` values, check firewall | |
| 212 | +| No changes captured | Table not in `tables` list | Add the table to the `tables` configuration | |
| 213 | +| Unstable element IDs | No primary key | Add primary key or configure `tableKeys` | |
| 214 | +| `binlog_row_image must be FULL` | Row image not complete | Set `binlog_row_image = FULL` in `my.cnf` and restart | |
| 215 | + |
| 216 | +### MySQL Permissions Checklist |
| 217 | + |
| 218 | +Your database user needs: |
| 219 | + |
| 220 | +```sql |
| 221 | +-- Required permissions |
| 222 | +GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'drasi_user'@'%'; |
| 223 | +GRANT SELECT ON mydb.* TO 'drasi_user'@'%'; |
| 224 | +FLUSH PRIVILEGES; |
| 225 | +``` |
| 226 | + |
| 227 | +## Known limitations |
| 228 | + |
| 229 | +- Packets larger than 16 MB are not supported. |
| 230 | +- DDL changes (schema migrations) during streaming may require a source restart. |
| 231 | + |
| 232 | +## Documentation resources |
| 233 | + |
| 234 | +<div class="card-grid card-grid--2"> |
| 235 | + <a href="https://github.com/drasi-project/drasi-core/blob/main/components/sources/mysql/README.md" target="_blank" rel="noopener"> |
| 236 | + <div class="unified-card unified-card--tutorials"> |
| 237 | + <div class="unified-card-icon"><i class="fab fa-github"></i></div> |
| 238 | + <div class="unified-card-content"> |
| 239 | + <h3 class="unified-card-title">MySQL Source README</h3> |
| 240 | + <p class="unified-card-summary">Implementation notes, prerequisites, and behavior details</p> |
| 241 | + </div> |
| 242 | + </div> |
| 243 | + </a> |
| 244 | + <a href="https://crates.io/crates/drasi-source-mysql" target="_blank" rel="noopener"> |
| 245 | + <div class="unified-card unified-card--howto"> |
| 246 | + <div class="unified-card-icon"><i class="fas fa-box"></i></div> |
| 247 | + <div class="unified-card-content"> |
| 248 | + <h3 class="unified-card-title">drasi-source-mysql on crates.io</h3> |
| 249 | + <p class="unified-card-summary">Package info and release history</p> |
| 250 | + </div> |
| 251 | + </div> |
| 252 | + </a> |
| 253 | +</div> |
0 commit comments