<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>MySQL Operations Guides on Netdata</title><link>https://www.netdata.cloud/guides/mysql/</link><description>Recent content in MySQL Operations Guides on Netdata</description><generator>Hugo</generator><language>en-us</language><atom:link href="https://www.netdata.cloud/guides/mysql/index.xml" rel="self" type="application/rss+xml"/><item><title>How MySQL actually works in production: a mental model for operators</title><link>https://www.netdata.cloud/guides/mysql/how-mysql-works-in-production/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/how-mysql-works-in-production/</guid><description>&lt;h1 id="how-mysql-actually-works-in-production-a-mental-model-for-operators">How MySQL actually works in production: a mental model for operators&lt;/h1>
&lt;p>MySQL is a connection-oriented request processor with a pluggable storage engine. In production, that engine is almost always InnoDB. Operating MySQL at scale means managing memory pressure, write-ahead log capacity, version-chain traversal, and fsync latency. The optimizer matters, but the stalls that wake you up start inside InnoDB.&lt;/p>
&lt;p>This guide maps the subsystems that fail in production. It assumes you know how to run &lt;code>SHOW PROCESSLIST&lt;/code> and need to move from symptoms to root cause: why the server stalls, why replication drifts, or why a fast query suddenly saturates disk I/O.&lt;/p></description></item><item><title>MySQL Aborted_connects and Aborted_clients climbing: diagnosis</title><link>https://www.netdata.cloud/guides/mysql/mysql-aborted-connections/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-aborted-connections/</guid><description>&lt;h1 id="mysql-aborted_connects-and-aborted_clients-climbing-diagnosis">MySQL Aborted_connects and Aborted_clients climbing: diagnosis&lt;/h1>
&lt;p>You notice &lt;code>Aborted_connects&lt;/code> or &lt;code>Aborted_clients&lt;/code> climbing on a production MySQL instance. Because these are cumulative counters, a steady upward slope means something is actively failing or dropping connections. In a busy system, a rising &lt;code>Aborted_connects&lt;/code> rate can trigger host blocking via &lt;code>max_connect_errors&lt;/code>, suddenly preventing legitimate clients from connecting. A rising &lt;code>Aborted_clients&lt;/code> rate usually shows up as application-side exceptions about closed connections, forcing retries that can cascade into connection exhaustion. The two counters track completely different failure modes: &lt;code>Aborted_connects&lt;/code> counts connection attempts that never finished authentication; &lt;code>Aborted_clients&lt;/code> counts connections that authenticated but then died unexpectedly. Treating them as the same metric leads to wrong fixes. Restarting the network stack will not fix a credential rotation bug, and increasing &lt;code>max_connections&lt;/code> will not fix a client killed by &lt;code>wait_timeout&lt;/code>.&lt;/p></description></item><item><title>MySQL adaptive hash index latch contention: high CPU, low throughput</title><link>https://www.netdata.cloud/guides/mysql/mysql-adaptive-hash-index-latch-contention/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-adaptive-hash-index-latch-contention/</guid><description>&lt;h1 id="mysql-adaptive-hash-index-latch-contention-high-cpu-low-throughput">MySQL adaptive hash index latch contention: high CPU, low throughput&lt;/h1>
&lt;p>Burning CPU while barely answering queries: OS user time near 100%, application latency spiking, and &lt;code>Questions&lt;/code> flat or falling. &lt;code>Threads_connected&lt;/code> is high but &lt;code>Threads_running&lt;/code> stays low, and disk I/O is quiet. This pattern matches an Adaptive Hash Index (AHI) latch storm.&lt;/p>
&lt;p>InnoDB builds an in-memory hash index over frequently accessed B-tree pages to speed lookups. Since MySQL 5.7, the latch is partitioned into &lt;code>innodb_adaptive_hash_index_parts&lt;/code> (default 8). Under high concurrency, especially point lookups on a hot index, threads can collide on the same partition latch and spin instead of executing. CPU saturates while throughput collapses.&lt;/p></description></item><item><title>MySQL authentication failure spike: brute force vs broken credential rotation</title><link>https://www.netdata.cloud/guides/mysql/mysql-auth-failure-rate/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-auth-failure-rate/</guid><description>&lt;h1 id="mysql-authentication-failure-spike-brute-force-vs-broken-credential-rotation">MySQL authentication failure spike: brute force vs broken credential rotation&lt;/h1>
&lt;p>You get paged because &lt;code>Aborted_connects&lt;/code> is climbing. The error log shows a wall of authentication failures, application dashboards are yellow, and someone in security is asking if this is an attack. Before you block IP addresses or rotate passwords, you need to know which failure mode you are dealing with. External brute force and internal broken credential rotation produce the same MySQL status counters, but the fixes are opposite. One requires closing the network window and flushing blocked hosts. The other requires finding the application instance that missed the new secret.&lt;/p></description></item><item><title>MySQL binary logs filling the disk: expiry, lagging replicas, and purge</title><link>https://www.netdata.cloud/guides/mysql/mysql-binary-log-disk-full/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-binary-log-disk-full/</guid><description>&lt;h1 id="mysql-binary-logs-filling-the-disk-expiry-lagging-replicas-and-purge">MySQL binary logs filling the disk: expiry, lagging replicas, and purge&lt;/h1>
&lt;p>You get a disk-full alert on the MySQL primary. &lt;code>df -h&lt;/code> shows the data partition at 95%, and &lt;code>du&lt;/code> points to &lt;code>/var/lib/mysql/binlog.*&lt;/code> consuming hundreds of gigabytes. Writes are about to fail.&lt;/p>
&lt;p>Binary logs are append-only. MySQL rotates to a new file at &lt;code>max_binlog_size&lt;/code> (default 1 GB), but rotation does not delete old files. Deletion only happens via automatic expiry or &lt;code>PURGE BINARY LOGS&lt;/code>. MySQL refuses to delete any binlog file that a connected replica has not yet consumed. In MySQL 5.7, the default expiry is never (&lt;code>expire_logs_days = 0&lt;/code>). In 8.0, the default is 30 days, but automatic purge cannot remove files that a connected replica still needs. A replica lagging past the expiry window therefore causes unbounded growth.&lt;/p></description></item><item><title>MySQL connection exhaustion: detection, diagnosis, and prevention</title><link>https://www.netdata.cloud/guides/mysql/mysql-connection-exhaustion/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-connection-exhaustion/</guid><description>&lt;h1 id="mysql-connection-exhaustion-detection-diagnosis-and-prevention">MySQL connection exhaustion: detection, diagnosis, and prevention&lt;/h1>
&lt;p>ERROR 1040 (HY000): Too many connections. Health checks fail. Users cannot sign in. If you configured an admin account correctly, a break-glass session may still get through on the reserved slot, and &lt;code>SELECT 1&lt;/code> returns. MySQL is running, but the connection pool is a wall.&lt;/p>
&lt;p>This is a hard cliff. One moment queries flow; the next, every new TCP handshake to port 3306 is rejected. The server does not queue connections. Whether the root cause is a connection leak, a retry storm, or genuine overload from slow queries, the symptom is the same: &lt;code>Threads_connected&lt;/code> has reached &lt;code>max_connections&lt;/code>.&lt;/p></description></item><item><title>MySQL Created_tmp_disk_tables: temp tables spilling to disk</title><link>https://www.netdata.cloud/guides/mysql/mysql-temp-tables-on-disk/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-temp-tables-on-disk/</guid><description>&lt;h1 id="mysql-created_tmp_disk_tables-temp-tables-spilling-to-disk">MySQL Created_tmp_disk_tables: temp tables spilling to disk&lt;/h1>
&lt;p>Queries that &lt;code>GROUP BY&lt;/code>, &lt;code>ORDER BY&lt;/code>, &lt;code>DISTINCT&lt;/code>, or materialize derived results build internal temporary tables. When those tables exceed memory limits, MySQL spills them to disk. The status counter &lt;code>Created_tmp_disk_tables&lt;/code> tracks this, and its ratio to &lt;code>Created_tmp_tables&lt;/code> is the signal to watch during a latency incident.&lt;/p>
&lt;p>A low ratio is normal. A high ratio means queries pay a random-disk penalty for intermediate results. You see that as rising query latency, increased disk I/O on the data directory, and connection pile-up. This guide covers how to read the ratio, find the offending patterns, and fix them without just adding RAM.&lt;/p></description></item><item><title>MySQL ERROR 1040 (HY000): Too many connections - causes and fixes</title><link>https://www.netdata.cloud/guides/mysql/mysql-too-many-connections/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-too-many-connections/</guid><description>&lt;h1 id="mysql-error-1040-hy000-too-many-connections---causes-and-fixes">MySQL ERROR 1040 (HY000): Too many connections - causes and fixes&lt;/h1>
&lt;p>Once &lt;code>Threads_connected&lt;/code> reaches &lt;code>max_connections&lt;/code>, MySQL returns &lt;code>ERROR 1040 (HY000)&lt;/code> to every new connection attempt before authentication. The server is not down; it is full.&lt;/p>
&lt;p>This error is usually a symptom. Connections may be leaking from the application, a cache stampede may have flooded the pool, or slow queries may be holding slots open longer than expected. MySQL reserves one extra connection for users with &lt;code>CONNECTION_ADMIN&lt;/code> (or the deprecated &lt;code>SUPER&lt;/code> privilege). If that slot is free, an operator can still connect. If an app user has taken it, you may need to restart.&lt;/p></description></item><item><title>MySQL ERROR 1045 (28000): Access denied for user - diagnosis</title><link>https://www.netdata.cloud/guides/mysql/mysql-access-denied-for-user/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-access-denied-for-user/</guid><description>&lt;h1 id="mysql-error-1045-28000-access-denied-for-user---diagnosis">MySQL ERROR 1045 (28000): Access denied for user - diagnosis&lt;/h1>
&lt;p>When you see &lt;code>ERROR 1045 (28000): Access denied for user 'app'@'10.0.0.5' (using password: YES)&lt;/code>, the connection never reached the query parser. MySQL rejected it during authentication, incremented &lt;code>Aborted_connects&lt;/code>, and returned SQLSTATE &lt;code>28000&lt;/code>. The error always includes the effective user and host as seen by the server. This is your first and most important clue.&lt;/p>
&lt;p>This error has four root causes in production: wrong credentials, user@host mismatch, authentication plugin incompatibility, and host-level blocking from accumulated connection errors. A brute-force probe and a misconfigured deploy look identical from the server side, so diagnosis hinges on correlating the error pattern with connection metrics and the host cache.&lt;/p></description></item><item><title>MySQL ERROR 1205: Lock wait timeout exceeded; try restarting transaction</title><link>https://www.netdata.cloud/guides/mysql/mysql-lock-wait-timeout-exceeded/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-lock-wait-timeout-exceeded/</guid><description>&lt;h1 id="mysql-error-1205-lock-wait-timeout-exceeded-try-restarting-transaction">MySQL ERROR 1205: Lock wait timeout exceeded; try restarting transaction&lt;/h1>
&lt;p>&lt;code>ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction&lt;/code> appears when one transaction holds an InnoDB row lock so long that another transaction exhausts &lt;code>innodb_lock_wait_timeout&lt;/code> (default 50 seconds). Unlike a deadlock, which InnoDB resolves automatically, a timeout means a blocker is still active. The root cause is almost always a long-running transaction or hot row contention. Find it before it cascades into a wider outage.&lt;/p></description></item><item><title>MySQL ERROR 1213: Deadlock found when trying to get lock; try restarting transaction</title><link>https://www.netdata.cloud/guides/mysql/mysql-deadlock-found/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-deadlock-found/</guid><description>&lt;h1 id="mysql-error-1213-deadlock-found-when-trying-to-get-lock-try-restarting-transaction">MySQL ERROR 1213: Deadlock found when trying to get lock; try restarting transaction&lt;/h1>
&lt;p>Your application logs show &lt;code>ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction&lt;/code>. One transaction was rolled back; the other completed normally. InnoDB broke a circular lock wait by selecting the cheaper transaction as the victim. A few deadlocks per hour in high-concurrency OLTP is normal. A sustained storm is not: it means transactions are colliding under load.&lt;/p></description></item><item><title>MySQL ERROR 1290: --read-only option so it cannot execute this statement</title><link>https://www.netdata.cloud/guides/mysql/mysql-replica-read-only-write-error/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-replica-read-only-write-error/</guid><description>&lt;h1 id="mysql-error-1290---read-only-option-so-it-cannot-execute-this-statement">MySQL ERROR 1290: &amp;ndash;read-only option so it cannot execute this statement&lt;/h1>
&lt;p>A write that fails with &lt;code>ERROR 1290 (HY000): The MySQL server is running with the --read-only option so it cannot execute this statement&lt;/code> is a routing or topology problem, not a query problem. The server refuses the statement because &lt;code>read_only&lt;/code> or &lt;code>super_read_only&lt;/code> is enabled. You are likely sending writes to a replica, a recently promoted primary that never cleared its read-only flag, or a node correctly enforcing &lt;code>super_read_only&lt;/code>. Confirm the instance role and fix the write path.&lt;/p></description></item><item><title>MySQL ERROR 2006/2013: MySQL server has gone away -- causes and fixes</title><link>https://www.netdata.cloud/guides/mysql/mysql-server-has-gone-away/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-server-has-gone-away/</guid><description>&lt;h1 id="mysql-error-20062013-mysql-server-has-gone-away----causes-and-fixes">MySQL ERROR 2006/2013: MySQL server has gone away &amp;ndash; causes and fixes&lt;/h1>
&lt;p>ERROR 2006 (CR_SERVER_GONE_ERROR) and ERROR 2013 (CR_SERVER_LOST) produce the messages &amp;ldquo;MySQL server has gone away&amp;rdquo; and &amp;ldquo;Lost connection during query.&amp;rdquo; They often appear together, but they indicate different failures. ERROR 2006 means the server closed a connection the client believed was valid. ERROR 2013 means the connection dropped while a query was executing or results were transferring.&lt;/p>
&lt;p>Treating them identically leads to incorrect fixes. Raising &lt;code>max_connections&lt;/code> does not stop idle timeouts. Tuning timeouts does not fix an OOM kill. Before changing configuration, determine whether the MySQL process restarted. A stable process points to timeout or packet mismatches. A restarted process points to a crash or memory exhaustion.&lt;/p></description></item><item><title>MySQL ERROR 24 (HY000): Too many open files -- raising open_files_limit</title><link>https://www.netdata.cloud/guides/mysql/mysql-too-many-open-files/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-too-many-open-files/</guid><description>&lt;h1 id="mysql-error-24-hy000-too-many-open-files----raising-open_files_limit">MySQL ERROR 24 (HY000): Too many open files &amp;ndash; raising open_files_limit&lt;/h1>
&lt;p>&lt;code>ERROR 24 (HY000): Too many open files&lt;/code> means the OS refused a file descriptor request because the &lt;code>mysqld&lt;/code> process hit its hard ceiling. Clients may see &lt;code>Can't create/write to file&lt;/code> with &lt;code>errno: 24&lt;/code>. Tables that were accessible moments ago fail to open, and new connections may be rejected even though &lt;code>Threads_connected&lt;/code> is well below &lt;code>max_connections&lt;/code>.&lt;/p>
&lt;p>MySQL holds file descriptors for cached tables, client connections, binary logs, relay logs, and on-disk temporary tables. When combined demand exceeds the OS-enforced limit, the server returns errno 24. Unlike connection exhaustion, which is gated by &lt;code>max_connections&lt;/code>, file descriptor exhaustion is gated by &lt;code>open_files_limit&lt;/code> and the OS limits that enforce it. Raising &lt;code>open_files_limit&lt;/code> in &lt;code>my.cnf&lt;/code> is not enough if systemd, PAM, or the shell ulimit blocks the request.&lt;/p></description></item><item><title>MySQL FLUSH TABLES WITH READ LOCK stall: backups that freeze the server</title><link>https://www.netdata.cloud/guides/mysql/mysql-flush-tables-with-read-lock-stall/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-flush-tables-with-read-lock-stall/</guid><description>&lt;h1 id="mysql-flush-tables-with-read-lock-stall-backups-that-freeze-the-server">MySQL FLUSH TABLES WITH READ LOCK stall: backups that freeze the server&lt;/h1>
&lt;p>Your application suddenly cannot write. &lt;code>Threads_connected&lt;/code> climbs toward &lt;code>max_connections&lt;/code>, but &lt;code>Questions&lt;/code> flatlines. The last change was a backup job that started ten minutes ago. The culprit is almost always &lt;code>FLUSH TABLES WITH READ LOCK&lt;/code> (FTWRL), and the damage is caused not by the lock itself but by what happens while the server waits to acquire it.&lt;/p>
&lt;p>FTWRL is triggered by &lt;code>mysqldump --master-data&lt;/code>, &lt;code>mysqldump --lock-tables&lt;/code>, and similar tools that need a consistent logical backup. It attempts to close all open tables and acquire a global read lock. While it waits for a long-running query to finish, new writes are already blocked. The result is a whole-server freeze: the query rate drops to zero, connections pile up, and the application sees cascading timeouts.&lt;/p></description></item><item><title>MySQL full table scans: Handler_read_rnd_next and the missing index</title><link>https://www.netdata.cloud/guides/mysql/mysql-full-table-scans/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-full-table-scans/</guid><description>&lt;h1 id="mysql-full-table-scans-handler_read_rnd_next-and-the-missing-index">MySQL full table scans: Handler_read_rnd_next and the missing index&lt;/h1>
&lt;p>You get paged because query latency is spiking. &lt;code>Slow_queries&lt;/code> is climbing. &lt;code>Handler_read_rnd_next&lt;/code> has jumped five-fold over its baseline and keeps rising. Connections, CPU, and buffer pool hit ratio look fine. The culprit is usually a new full table scan after a deploy, schema change, or query pattern shift.&lt;/p>
&lt;p>&lt;code>Handler_read_rnd_next&lt;/code> increments when the storage engine reads the next row during a table scan or sorted retrieval. In a healthy OLTP system, &lt;code>Handler_read_key&lt;/code> dominates and &lt;code>Handler_read_rnd_next&lt;/code> stays flat relative to query volume. When the ratio inverts, you are looking at a query plan regression, a missing index, or an optimizer decision gone wrong.&lt;/p></description></item><item><title>MySQL gap locks and next-key locks: surprising deadlocks under REPEATABLE READ</title><link>https://www.netdata.cloud/guides/mysql/mysql-gap-locks-next-key-locks/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-gap-locks-next-key-locks/</guid><description>&lt;h1 id="mysql-gap-locks-and-next-key-locks-surprising-deadlocks-under-repeatable-read">MySQL gap locks and next-key locks: surprising deadlocks under REPEATABLE READ&lt;/h1>
&lt;p>MySQL deadlocks in production frequently involve transactions that modify apparently unrelated rows. Two concurrent UPDATEs with narrow WHERE clauses collide, or an UPDATE blocks every INSERT into the table. The cause is usually REPEATABLE READ combined with InnoDB next-key locking and a missing or non-unique index.&lt;/p>
&lt;p>Under REPEATABLE READ, the default in MySQL, InnoDB does not lock only matching rows. To prevent phantom reads, it locks the gaps between index entries. When no suitable index exists, or when the optimizer scans a non-unique index, a targeted UPDATE escalates into a range lock covering far more of the table than the predicate suggests.&lt;/p></description></item><item><title>MySQL Got error 28 from storage engine / No space left on device — recovery</title><link>https://www.netdata.cloud/guides/mysql/mysql-disk-full-no-space-left/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-disk-full-no-space-left/</guid><description>&lt;h1 id="mysql-got-error-28-from-storage-engine--no-space-left-on-device--recovery">MySQL Got error 28 from storage engine / No space left on device — recovery&lt;/h1>
&lt;p>When &lt;code>Got error 28 from storage engine&lt;/code> appears, the underlying filesystem is at 100%. MySQL needs writable space for InnoDB data files, redo logs, binary logs, temporary tables, relay logs, and slow query logs. Writes fail immediately. Affected threads enter a retry loop, logging warnings until an operator frees space or kills the operation.&lt;/p>
&lt;p>The most dangerous scenario is the redo log filling up. If checkpoint age approaches capacity, InnoDB forces aggressive synchronous flushing. Under sustained pressure this can trigger an unclean shutdown and crash recovery on restart. Replicas are similarly vulnerable: a full relay log partition stops the I/O thread and lets lag grow unboundedly, risking binlog expiry on the source before catch-up.&lt;/p></description></item><item><title>MySQL GTID errant transactions: detecting replication divergence</title><link>https://www.netdata.cloud/guides/mysql/mysql-gtid-errant-transactions/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-gtid-errant-transactions/</guid><description>&lt;h1 id="mysql-gtid-errant-transactions-detecting-replication-divergence">MySQL GTID errant transactions: detecting replication divergence&lt;/h1>
&lt;p>Before a planned failover, or after an orchestrator aborts with a GTID consistency error, replication can appear healthy: &lt;code>SHOW REPLICA STATUS&lt;/code> reports both threads running, &lt;code>Seconds_Behind_Source&lt;/code> is near zero, and the error log is quiet. Yet comparing GTID sets between source and replica reveals mismatching numbers. Errant transactions are GTIDs present in a replica&amp;rsquo;s &lt;code>gtid_executed&lt;/code> set that the source never generated.&lt;/p>
&lt;p>Ordinary lag resolves as the replica catches up. Errant transactions represent true divergence. Promoting a replica with extra GTIDs propagates those transactions into the new source and downstream replicas, creating split-brain that is expensive to reverse. This guide covers distinguishing benign lag from dangerous divergence, pinpointing offending GTIDs, and deciding between empty-transaction injection and a full rebuild.&lt;/p></description></item><item><title>MySQL InnoDB buffer pool hit ratio collapse: the cliff edge</title><link>https://www.netdata.cloud/guides/mysql/mysql-buffer-pool-hit-ratio-collapse/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-buffer-pool-hit-ratio-collapse/</guid><description>&lt;h1 id="mysql-innodb-buffer-pool-hit-ratio-collapse-the-cliff-edge">MySQL InnoDB buffer pool hit ratio collapse: the cliff edge&lt;/h1>
&lt;p>Your OLTP queries were running in single-digit milliseconds. Now every query is taking seconds, the disk subsystem is saturated, &lt;code>Threads_running&lt;/code> is climbing toward &lt;code>max_connections&lt;/code>, and the buffer pool hit ratio, which sat at 99.9% for months, just fell through 95% and keeps dropping.&lt;/p>
&lt;p>This is the InnoDB buffer pool cliff edge. When the working set exceeds the buffer pool, pages are evicted before they can be reused. Every miss becomes a physical disk read. The degradation is non-linear: 99.9% to 99% is a slow bleed, 99% to 95% is rapid, and below 95% disk saturation, uniform latency inflation, and connection exhaustion turn a capacity problem into an availability incident.&lt;/p></description></item><item><title>MySQL InnoDB checkpoint age: the redo log capacity signal nobody watches</title><link>https://www.netdata.cloud/guides/mysql/mysql-checkpoint-age-monitoring/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-checkpoint-age-monitoring/</guid><description>&lt;h1 id="mysql-innodb-checkpoint-age-the-redo-log-capacity-signal-nobody-watches">MySQL InnoDB checkpoint age: the redo log capacity signal nobody watches&lt;/h1>
&lt;p>Checkpoint age is the distance between the current InnoDB log sequence number (LSN) and the last checkpoint LSN. It measures how much of the circular redo log is occupied by changes not yet flushed to data files. When this age approaches redo log capacity, InnoDB escalates flushing aggressiveness until it runs out of options and stalls all writes.&lt;/p>
&lt;p>Standard MySQL does not expose &lt;code>Innodb_checkpoint_age&lt;/code> as a status variable. Depending on version, you must parse &lt;code>SHOW ENGINE INNODB STATUS&lt;/code>, enable a disabled-by-default &lt;code>INNODB_METRICS&lt;/code> counter, or compute the delta from MySQL 8.0.30+ redo status variables. MySQL 8.0.30 replaced &lt;code>innodb_log_file_size&lt;/code> and &lt;code>innodb_log_files_in_group&lt;/code> with &lt;code>innodb_redo_log_capacity&lt;/code>. &lt;!-- TODO: verify whether leaving the new variable unset on upgrade always reduces capacity, or if MySQL computes it from legacy settings when present. -->&lt;/p></description></item><item><title>MySQL InnoDB history list length growing: purge lag explained</title><link>https://www.netdata.cloud/guides/mysql/mysql-history-list-length-growing/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-history-list-length-growing/</guid><description>&lt;h1 id="mysql-innodb-history-list-length-growing-purge-lag-explained">MySQL InnoDB history list length growing: purge lag explained&lt;/h1>
&lt;p>If query latency climbs across every table and no single query stands out, check the InnoDB history list length. It tracks unpurged undo records: MVCC debt. When purge falls behind, every consistent read walks longer version chains, and the slowdown is global. Unlike a slow query, this debt is invisible to conventional query analysis.&lt;/p>
&lt;p>In MySQL 8.0, the programmatic source for this metric is &lt;code>trx_rseg_history_len&lt;/code> in &lt;code>information_schema.INNODB_METRICS&lt;/code>. &lt;!-- TODO: verify whether Innodb_history_list_length was removed from SHOW GLOBAL STATUS in MySQL 8.0 or only in specific versions --> Despite being labeled &lt;code>status_counter&lt;/code> in the metrics table, &lt;code>trx_rseg_history_len&lt;/code> behaves as a gauge: it rises when purge lags and falls when purge catches up.&lt;/p></description></item><item><title>MySQL InnoDB redo log checkpoint stall: when all writes freeze</title><link>https://www.netdata.cloud/guides/mysql/mysql-redo-log-checkpoint-stall/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-redo-log-checkpoint-stall/</guid><description>&lt;h1 id="mysql-innodb-redo-log-checkpoint-stall-when-all-writes-freeze">MySQL InnoDB redo log checkpoint stall: when all writes freeze&lt;/h1>
&lt;p>InnoDB redo log checkpoint stalls freeze all writes synchronously when checkpoint age reaches the end of the circular redo log. INSERTs, UPDATEs, and DELETEs that complete in milliseconds hang for seconds. &lt;code>Threads_running&lt;/code> climbs while the &lt;code>Questions&lt;/code> rate collapses. Read queries may still return initially, but soon every connection waits for a write lock or commit acknowledgment. Then throughput recovers just as abruptly. This is not a disk failure, deadlock, or runaway query. It is MySQL&amp;rsquo;s write path running out of runway.&lt;/p></description></item><item><title>MySQL InnoDB row lock contention: finding who blocks whom</title><link>https://www.netdata.cloud/guides/mysql/mysql-row-lock-contention/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-row-lock-contention/</guid><description>&lt;h1 id="mysql-innodb-row-lock-contention-finding-who-blocks-whom">MySQL InnoDB row lock contention: finding who blocks whom&lt;/h1>
&lt;p>Queries that normally finish in milliseconds take seconds. &lt;code>Threads_running&lt;/code> climbs while &lt;code>Questions&lt;/code> stalls. &lt;code>SHOW PROCESSLIST&lt;/code> shows active threads, yet the database is frozen. That is the shape of InnoDB row lock contention: transactions are waiting to release row-level locks, and the queue is growing.&lt;/p>
&lt;p>Row lock contention differs from a metadata lock cascade. Metadata locks block DDL and DML at the table level and live in &lt;code>performance_schema.metadata_locks&lt;/code>. Row locks are held by open InnoDB transactions and block at the row, gap, or next-key level. Rising &lt;code>Innodb_row_lock_current_waits&lt;/code> alongside rising &lt;code>Threads_running&lt;/code> signals a live contention crisis. The goal is to identify the blocker, the waiter, and the lock footprint so you can break the chain without guessing.&lt;/p></description></item><item><title>MySQL innodb_buffer_pool_size tuning: 60-80% of RAM and when that breaks</title><link>https://www.netdata.cloud/guides/mysql/mysql-buffer-pool-sizing/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-buffer-pool-sizing/</guid><description>&lt;h1 id="mysql-innodb_buffer_pool_size-tuning-60-80-of-ram-and-when-that-breaks">MySQL innodb_buffer_pool_size tuning: 60-80% of RAM and when that breaks&lt;/h1>
&lt;p>The 60-80% rule works for a bare-metal host running only MySQL. In containers, shared hardware, and high-connection-count environments, it is a hazard. Size the pool against aligned allocation, cgroup limits, per-connection memory, and OS headroom. Do not size it as a percentage of total RAM.&lt;/p>
&lt;h2 id="what-the-buffer-pool-costs">What the buffer pool costs&lt;/h2>
&lt;p>InnoDB caches data and index pages in a fixed-size pool. Every read and write touches it. When the working set fits entirely in memory, queries avoid disk. When it does not, InnoDB evicts pages and disk reads dominate latency.&lt;/p></description></item><item><title>MySQL Innodb_buffer_pool_wait_free > 0: buffer pool memory pressure</title><link>https://www.netdata.cloud/guides/mysql/mysql-buffer-pool-wait-free/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-buffer-pool-wait-free/</guid><description>&lt;h1 id="mysql-innodb_buffer_pool_wait_free--0-buffer-pool-memory-pressure">MySQL Innodb_buffer_pool_wait_free &amp;gt; 0: buffer pool memory pressure&lt;/h1>
&lt;p>&lt;code>Innodb_buffer_pool_wait_free&lt;/code> increments when InnoDB must synchronously flush dirty pages to make room for new reads. A sustained nonzero rate means queries are waiting on disk writes before they can proceed. Unlike the buffer pool hit ratio, which can stay above 99% while the system stalls, &lt;code>wait_free&lt;/code> confirms the buffer pool is operating at its limit.&lt;/p>
&lt;p>This is the Buffer Pool Cliff pattern: once the working set exceeds available clean pages, performance degrades non-linearly, disk I/O saturates, and threads pile up.&lt;/p></description></item><item><title>MySQL innodb_deadlock_detect=OFF: when deadlock detection becomes the bottleneck</title><link>https://www.netdata.cloud/guides/mysql/mysql-deadlock-detect-off-high-concurrency/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-deadlock-detect-off-high-concurrency/</guid><description>&lt;h1 id="mysql-innodb_deadlock_detectoff-when-deadlock-detection-becomes-the-bottleneck">MySQL innodb_deadlock_detect=OFF: when deadlock detection becomes the bottleneck&lt;/h1>
&lt;p>At extreme concurrency, InnoDB&amp;rsquo;s deadlock detector can become the bottleneck. It traverses the wait-for graph on every lock enqueue. That cost is usually negligible until thousands of concurrent writing transactions hit a small set of hot rows. When traversal itself saturates CPU, throughput collapses even though disks are idle and the buffer pool is warm.&lt;/p>
&lt;p>&lt;code>innodb_deadlock_detect=OFF&lt;/code> removes that traversal. Instead of instant deadlock detection, InnoDB relies exclusively on &lt;code>innodb_lock_wait_timeout&lt;/code> to break cycles. The blocked transaction waits, holding its locks, until the timeout expires. This is not a generic performance tuning knob. It is a narrow, high-risk tradeoff that converts instant rollback into delayed timeout, and it is appropriate only when you have confirmed through testing that deadlock detection is the bottleneck.&lt;/p></description></item><item><title>MySQL Innodb_log_waits > 0: the log buffer is too small (not a checkpoint stall)</title><link>https://www.netdata.cloud/guides/mysql/mysql-log-buffer-waits/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-log-buffer-waits/</guid><description>&lt;h1 id="mysql-innodb_log_waits--0-the-log-buffer-is-too-small-not-a-checkpoint-stall">MySQL Innodb_log_waits &amp;gt; 0: the log buffer is too small (not a checkpoint stall)&lt;/h1>
&lt;p>InnoDB increments &lt;code>Innodb_log_waits&lt;/code> every time a thread waits because the log buffer is full. A sustained nonzero rate means the buffer cannot absorb your write burst, or the storage layer cannot drain it fast enough.&lt;/p>
&lt;p>This is not a checkpoint stall. Checkpoint stalls happen when the on-disk redo log fills and InnoDB forces synchronous dirty-page flushing. &lt;code>Innodb_log_waits&lt;/code> measures in-memory log buffer pressure only. Confusing the two leads to tuning redo log file size while the real problem persists.&lt;/p></description></item><item><title>MySQL innodb_redo_log_capacity sizing: how big should the redo log be</title><link>https://www.netdata.cloud/guides/mysql/mysql-redo-log-capacity-sizing/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-redo-log-capacity-sizing/</guid><description>&lt;h1 id="mysql-innodb_redo_log_capacity-sizing-how-big-should-the-redo-log-be">MySQL innodb_redo_log_capacity sizing: how big should the redo log be&lt;/h1>
&lt;p>An undersized InnoDB redo log is a common cause of MySQL write stalls. When redo generation outpaces dirty-page flushing, checkpoint age advances until InnoDB enters synchronous flushing and user writes block.&lt;/p>
&lt;p>Since MySQL 8.0.30, &lt;code>innodb_redo_log_capacity&lt;/code> replaces &lt;code>innodb_log_file_size&lt;/code> and &lt;code>innodb_log_files_in_group&lt;/code>. Resizing no longer requires a restart, but the sizing logic is unchanged: capacity must absorb peak write rates without pushing checkpoint age into the synchronous-flush zone.&lt;/p></description></item><item><title>MySQL InnoDB: Database page corruption — detection and recovery</title><link>https://www.netdata.cloud/guides/mysql/mysql-innodb-page-corruption/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-innodb-page-corruption/</guid><description>&lt;h1 id="mysql-innodb-database-page-corruption--detection-and-recovery">MySQL InnoDB: Database page corruption — detection and recovery&lt;/h1>
&lt;p>Your error log shows &lt;code>InnoDB: Database page corruption on disk or a failed file read&lt;/code>. MySQL may abort the connection, mark the tablespace read-only, or crash. Page corruption is a storage-layer failure, not a query bug: a 16KB InnoDB page failed checksum validation.&lt;/p>
&lt;p>The critical distinction is between secondary index corruption, which is rebuildable without data loss, and clustered index corruption, which affects the table data itself. Detect the failure, classify the damage, extract what you can, and rebuild safely.&lt;/p></description></item><item><title>MySQL long-running transactions: detecting and killing the silent blocker</title><link>https://www.netdata.cloud/guides/mysql/mysql-long-running-transactions/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-long-running-transactions/</guid><description>&lt;h1 id="mysql-long-running-transactions-detecting-and-killing-the-silent-blocker">MySQL long-running transactions: detecting and killing the silent blocker&lt;/h1>
&lt;p>&lt;code>Threads_running&lt;/code> climbs. A DDL operation that should take seconds is stuck for minutes. Storage grows steadily with no matching data increase. The cause is often a single idle transaction in &lt;code>INNODB_TRX&lt;/code>, holding row locks and an MVCC read view long after its last query finished. It does not appear in the slow query log and may have no active query string. Left alone, it blocks InnoDB purge, inflates the history list, and can trigger a metadata lock cascade that fills the connection pool.&lt;/p></description></item><item><title>MySQL metadata lock cascade: how one ALTER TABLE freezes a whole table</title><link>https://www.netdata.cloud/guides/mysql/mysql-metadata-lock-cascade/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-metadata-lock-cascade/</guid><description>&lt;h1 id="mysql-metadata-lock-cascade-how-one-alter-table-freezes-a-whole-table">MySQL metadata lock cascade: how one ALTER TABLE freezes a whole table&lt;/h1>
&lt;p>You run an &lt;code>ALTER TABLE&lt;/code> to add an index. Seconds later, health checks fail for queries that touch only that table. Other tables work fine. CPU and disk are idle. The connection pool fills. &lt;code>SHOW ENGINE INNODB STATUS&lt;/code> shows no row lock waits. The culprit is a metadata lock cascade, not InnoDB contention.&lt;/p>
&lt;p>This happens when DDL requests an exclusive metadata lock (MDL) on a table already protected by a shared MDL held by a long-running or idle transaction. The DDL waits. Subsequent DML on that table queues behind it. The queue grows until the connection pool exhausts and the application times out. Because the outage is isolated to one table and leaves no trace in InnoDB lock metrics, it is easy to misdiagnose as a network blip or a runaway query.&lt;/p></description></item><item><title>MySQL monitoring checklist: the signals every production instance needs</title><link>https://www.netdata.cloud/guides/mysql/mysql-monitoring-checklist/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-monitoring-checklist/</guid><description>&lt;h1 id="mysql-monitoring-checklist-the-signals-every-production-instance-needs">MySQL monitoring checklist: the signals every production instance needs&lt;/h1>
&lt;p>Most production incidents involving MySQL stem from missing observability into specific internal subsystems. Connection saturation, buffer pool thrashing, and replication lag can degrade a healthy cluster into an outage if the right signals are not monitored.&lt;/p>
&lt;p>This checklist serves as a tiered operational reference for senior engineers and SREs. It defines the exact metrics needed to keep MySQL instances available, fast, and reliable, scaling from basic survival metrics to expert-level internals. Use it to validate existing dashboards or baseline monitoring for a new deployment.&lt;/p></description></item><item><title>MySQL monitoring maturity model: from survival to expert</title><link>https://www.netdata.cloud/guides/mysql/mysql-monitoring-maturity-model/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-monitoring-maturity-model/</guid><description>&lt;h1 id="mysql-monitoring-maturity-model-from-survival-to-expert">MySQL monitoring maturity model: from survival to expert&lt;/h1>
&lt;p>Most MySQL monitoring stacks grow reactively. A team starts with a liveness check and disk alerting. An incident exposes a gap, a new signal gets added, and the cycle repeats. The result is uneven coverage: strong in areas that caused past outages, blind in areas that will cause the next one.&lt;/p>
&lt;p>This article maps MySQL monitoring into four capability levels. Use it as a self-assessment, not a checklist to max out. Every level includes signals the playbook identifies as operationally important, along with the failure modes they catch. If you are missing an entire category at your current level, that is your highest-priority gap.&lt;/p></description></item><item><title>MySQL online DDL still blocking: ALGORITHM, LOCK, and the copy phase</title><link>https://www.netdata.cloud/guides/mysql/mysql-online-ddl-blocking/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-online-ddl-blocking/</guid><description>&lt;h1 id="mysql-online-ddl-still-blocking-algorithm-lock-and-the-copy-phase">MySQL online DDL still blocking: ALGORITHM, LOCK, and the copy phase&lt;/h1>
&lt;p>Online DDL in MySQL is not lock-free. Even with &lt;code>ALGORITHM=INPLACE&lt;/code> or &lt;code>ALGORITHM=INSTANT&lt;/code>, and even with &lt;code>LOCK=NONE&lt;/code>, every online DDL operation passes through a brief window where it upgrades its metadata lock (MDL) to exclusive. That window is short, but it is real, and it is the single most common reason an &amp;ldquo;online&amp;rdquo; schema change still stalls a busy production table.&lt;/p></description></item><item><title>MySQL OOM-killed: buffer pool, per-connection buffers, and the kernel killer</title><link>https://www.netdata.cloud/guides/mysql/mysql-out-of-memory-oom-killed/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-out-of-memory-oom-killed/</guid><description>&lt;h1 id="mysql-oom-killed-buffer-pool-per-connection-buffers-and-the-kernel-killer">MySQL OOM-killed: buffer pool, per-connection buffers, and the kernel killer&lt;/h1>
&lt;p>MySQL disappears. Application logs fill with connection timeouts. &lt;code>Uptime&lt;/code> resets to near zero. In the kernel log: &lt;code>oom-kill: task mysqld&lt;/code> and its anonymous RSS. Orchestrators mark the pod &lt;code>OOMKilled&lt;/code> (exit code 137). To the application, this is a crash. To the kernel, mysqld was the largest memory consumer and the system ran out.&lt;/p>
&lt;p>OOM kills are gradual, then catastrophic. Memory pressure builds as connections open, temp tables materialize, and dirty pages accumulate. The buffer pool is the obvious consumer, but the killer often enters through the back door: a connection burst multiplies per-thread buffers, a container limit sits too close to the buffer pool size, or Transparent Huge Pages block reclamation. Map all allocators to prevent recurrence.&lt;/p></description></item><item><title>MySQL Opened_tables climbing: table_open_cache and open-files pressure</title><link>https://www.netdata.cloud/guides/mysql/mysql-table-open-cache-pressure/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-table-open-cache-pressure/</guid><description>&lt;h1 id="mysql-opened_tables-climbing-table_open_cache-and-open-files-pressure">MySQL Opened_tables climbing: table_open_cache and open-files pressure&lt;/h1>
&lt;p>Steadily climbing &lt;code>Opened_tables&lt;/code> with &lt;code>Open_tables&lt;/code> pinned near &lt;code>table_open_cache&lt;/code> means the instance is churning table file descriptors instead of reusing them. Each cache miss opens a table, consumes a file descriptor, and adds metadata lock overhead. The first symptom is usually sporadic query latency during peak traffic. Left unchecked, the instance exhausts its file descriptor limit and returns errors like &lt;code>Too many open files&lt;/code> or refuses connections.&lt;/p></description></item><item><title>MySQL privilege change auditing: GRANT, REVOKE, and unexpected SUPER</title><link>https://www.netdata.cloud/guides/mysql/mysql-privilege-changes-auditing/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-privilege-changes-auditing/</guid><description>&lt;h1 id="mysql-privilege-change-auditing-grant-revoke-and-unexpected-super">MySQL privilege change auditing: GRANT, REVOKE, and unexpected SUPER&lt;/h1>
&lt;p>Unexpected privilege changes are high-impact, low-frequency events. A spike in &lt;code>Com_grant&lt;/code>, an unknown account with &lt;code>SUPER&lt;/code>, or a &lt;code>GRANT ALL&lt;/code> outside a change window can signal privilege escalation, misconfigured automation, or migration debt. This guide covers how to detect, diagnose, and remove unauthorized grants and deprecated &lt;code>SUPER&lt;/code> privileges in production.&lt;/p>
&lt;h2 id="what-this-means">What this means&lt;/h2>
&lt;p>MySQL increments status counters for &lt;code>GRANT&lt;/code>, &lt;code>REVOKE&lt;/code>, &lt;code>CREATE USER&lt;/code>, &lt;code>ALTER USER&lt;/code>, and &lt;code>DROP USER&lt;/code>. The counters are cumulative; compute deltas over fixed intervals instead of reading absolute values.&lt;/p></description></item><item><title>MySQL purge lag from an idle transaction: the slow bleed</title><link>https://www.netdata.cloud/guides/mysql/mysql-purge-lag-idle-transaction/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-purge-lag-idle-transaction/</guid><description>&lt;h1 id="mysql-purge-lag-from-an-idle-transaction-the-slow-bleed">MySQL purge lag from an idle transaction: the slow bleed&lt;/h1>
&lt;p>Your OLTP workload slows over hours. No single query dominates the slow log. CPU and disk I/O are not saturated. Yet read latency climbs, throughput drifts downward, and the undo tablespace grows. The culprit is often a single idle transaction that opened a read view and never closed it. Under InnoDB&amp;rsquo;s default REPEATABLE READ isolation, that transaction pins the purge boundary. Every subsequent write appends to the undo log. The history list length grows without bound, and all MVCC reads traverse longer version chains.&lt;/p></description></item><item><title>MySQL query plan regression: when a query gets slow after a deploy or ANALYZE</title><link>https://www.netdata.cloud/guides/mysql/mysql-query-plan-regression/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-query-plan-regression/</guid><description>&lt;h1 id="mysql-query-plan-regression-when-a-query-gets-slow-after-a-deploy-or-analyze">MySQL query plan regression: when a query gets slow after a deploy or ANALYZE&lt;/h1>
&lt;p>A query that completed in milliseconds yesterday now times out. The deploy was clean, or maybe someone ran ANALYZE TABLE during maintenance. Slow_queries climbs, Handler_read_rnd_next jumps, and the same application code suddenly kills the database. The optimizer has changed how it executes one or more queries, and the new plan is far more expensive.&lt;/p>
&lt;p>Plan regressions are sharp step-changes, not gradual growth. They correlate tightly with specific events: a schema migration, an index drop, a bulk load that triggered auto-recalc, a manual ANALYZE TABLE, or a MySQL version upgrade. The cause is usually stale or shifted statistics, an optimizer behavior change, or a missing index the optimizer can no longer use.&lt;/p></description></item><item><title>MySQL relay log filling the replica disk: Relay_Log_Space and recovery</title><link>https://www.netdata.cloud/guides/mysql/mysql-relay-log-disk-full/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-relay-log-disk-full/</guid><description>&lt;h1 id="mysql-relay-log-filling-the-replica-disk-relay_log_space-and-recovery">MySQL relay log filling the replica disk: Relay_Log_Space and recovery&lt;/h1>
&lt;p>When &lt;code>SHOW REPLICA STATUS&lt;/code> shows &lt;code>Seconds_Behind_Source&lt;/code> climbing and &lt;code>Relay_Log_Space&lt;/code> growing, the SQL thread is not applying events as fast as the IO thread fetches them. Normally MySQL purges each relay log after the SQL thread finishes it, so total disk usage stays bounded. When apply cannot keep up, files accumulate. If the partition fills, the IO thread stops. No new events arrive, lag becomes unbounded, and if the source purges binary logs before recovery, the replica requires a full resync.&lt;/p></description></item><item><title>MySQL Replica_IO_Running / Replica_SQL_Running not Yes: replication stopped</title><link>https://www.netdata.cloud/guides/mysql/mysql-replica-io-sql-thread-stopped/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-replica-io-sql-thread-stopped/</guid><description>&lt;h1 id="mysql-replica_io_running--replica_sql_running-not-yes-replication-stopped">MySQL Replica_IO_Running / Replica_SQL_Running not Yes: replication stopped&lt;/h1>
&lt;p>&lt;code>SHOW REPLICA STATUS\G&lt;/code> (MySQL 8.0+) or &lt;code>SHOW SLAVE STATUS\G&lt;/code> (MySQL 5.7) shows &lt;code>Replica_IO_Running&lt;/code> or &lt;code>Replica_SQL_Running&lt;/code> is not &lt;code>Yes&lt;/code>. The IO thread may hang in &lt;code>Connecting&lt;/code>, or the SQL thread may stop with an error. Replication no longer makes progress. Lag grows without bound, and if the source purges binary logs before recovery, you face a full rebuild.&lt;/p>
&lt;p>Unlike many MySQL problems, a stopped replication thread does not self-heal. The SQL thread halts on the first apply error and waits for operator intervention. The IO thread retries automatically, but only up to the configured retry limit. &lt;code>Seconds_Behind_Source&lt;/code> can show &lt;code>0&lt;/code> even when the IO thread is disconnected and the SQL thread has consumed the relay log, so lag alone is not a reliable health signal.&lt;/p></description></item><item><title>MySQL replication lag spiral: Seconds_Behind_Source growing without bound</title><link>https://www.netdata.cloud/guides/mysql/mysql-replication-lag-spiral/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-replication-lag-spiral/</guid><description>&lt;h1 id="mysql-replication-lag-spiral-seconds_behind_source-growing-without-bound">MySQL replication lag spiral: Seconds_Behind_Source growing without bound&lt;/h1>
&lt;p>You check &lt;code>SHOW REPLICA STATUS&lt;/code> and see &lt;code>Seconds_Behind_Source&lt;/code> is not just elevated; it is climbing. Five minutes ago it was 60. Now it is 120. The replica is not catching up; it is falling further behind.&lt;/p>
&lt;p>This is a replication lag death spiral. The SQL apply thread (or threads) cannot replay events as fast as the source generates them. Relay logs accumulate. Lag compounds because longer apply queues mean larger effective transactions, longer lock holds, and greater exposure to blocking queries on the replica.&lt;/p></description></item><item><title>MySQL Seconds_Behind_Source is unreliable: measuring real replication lag</title><link>https://www.netdata.cloud/guides/mysql/mysql-seconds-behind-source-unreliable/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-seconds-behind-source-unreliable/</guid><description>&lt;h1 id="mysql-seconds_behind_source-is-unreliable-measuring-real-replication-lag">MySQL Seconds_Behind_Source is unreliable: measuring real replication lag&lt;/h1>
&lt;p>You run &lt;code>SHOW REPLICA STATUS&lt;/code> and see &lt;code>Seconds_Behind_Source = 0&lt;/code>. Both replication threads say &lt;code>Yes&lt;/code>. You assume the replica is current. During a source write burst, you fail over and discover hours of missing transactions. This happens because &lt;code>Seconds_Behind_Source&lt;/code> is not a real-time lag measurement. It is a timestamp diff between the replica&amp;rsquo;s clock and the timestamp of the event the SQL thread is currently applying. When the SQL thread reaches the end of the relay log, the metric snaps to zero even if the I/O thread has not fetched newer events. When the SQL thread stops, it returns NULL, which most lag alerts ignore. When the source was idle and then bursts, it jumps to the idle duration even though real lag is minimal. With parallel replication, it oscillates based on worker timing. For failover-critical decisions, you need a different measurement strategy.&lt;/p></description></item><item><title>MySQL Select_full_join > 0: joins running without an index</title><link>https://www.netdata.cloud/guides/mysql/mysql-select-full-join/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-select-full-join/</guid><description>&lt;h1 id="mysql-select_full_join--0-joins-running-without-an-index">MySQL Select_full_join &amp;gt; 0: joins running without an index&lt;/h1>
&lt;p>Select_full_join is climbing. In an OLTP system, this counter should stay at zero. Any sustained nonzero rate means at least one query is executing a join without a usable index, effectively performing a full cross-product scan on the joined table. The damage scales with table size. A single unindexed join against a million-row table can stall an otherwise healthy instance.&lt;/p>
&lt;p>This is not a buffer pool problem or a connection storm. It is a query correctness issue. The optimizer cannot find an index to resolve the join predicate, so it reads every row of the referenced table for each row of the driving table. In MySQL 8.0.20 and later, the execution engine uses hash join for these cases (block nested loop was removed), but the underlying pathology remains identical: missing index, catastrophic read amplification.&lt;/p></description></item><item><title>MySQL semi-synchronous replication stall: commits hanging on ACK</title><link>https://www.netdata.cloud/guides/mysql/mysql-semi-sync-replication-stall/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-semi-sync-replication-stall/</guid><description>&lt;h1 id="mysql-semi-synchronous-replication-stall-commits-hanging-on-ack">MySQL semi-synchronous replication stall: commits hanging on ACK&lt;/h1>
&lt;p>Commits suddenly take 10 seconds or more and then time out. On the MySQL primary, &lt;code>Threads_running&lt;/code> climbs while the commit rate flatlines. A moment later, commits resume, but &lt;code>Rpl_semi_sync_source_no_tx&lt;/code> is ticking upward. The primary is waiting for a semi-synchronous replica to acknowledge receipt of binlog events, and that ACK is not arriving fast enough or at all.&lt;/p>
&lt;p>Confirm the stall, find the missing ACK, and decide whether to fix the replica path or temporarily fall back to asynchronous replication.&lt;/p></description></item><item><title>MySQL slow after restart: buffer pool warm-up and the cold cache</title><link>https://www.netdata.cloud/guides/mysql/mysql-buffer-pool-not-warming-up/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-buffer-pool-not-warming-up/</guid><description>&lt;h1 id="mysql-slow-after-restart-buffer-pool-warm-up-and-the-cold-cache">MySQL slow after restart: buffer pool warm-up and the cold cache&lt;/h1>
&lt;p>You restart MySQL for maintenance, crash recovery, or a failover. Seconds later, query latency jumps from sub-millisecond to tens or hundreds of milliseconds. Disk read I/O saturates. The buffer pool hit ratio that normally sits above 99% has collapsed. There are no runaway queries, no lock waits, and no checkpoint stalls. The server is simply cold.&lt;/p>
&lt;p>After any restart, the InnoDB buffer pool starts empty. Every data page read misses memory and goes to disk, so &lt;code>Innodb_buffer_pool_reads&lt;/code> spikes. If the adaptive hash index is enabled, it is empty too. The server may accept client connections long before the pool is ready to serve production traffic. The issue looks like a capacity crisis, but it is usually transient and expected. Distinguishing a cold cache from a true capacity problem keeps you from chasing the wrong fixes during an incident.&lt;/p></description></item><item><title>MySQL slow commits with idle CPU: redo and binlog fsync pressure</title><link>https://www.netdata.cloud/guides/mysql/mysql-fsync-pressure-slow-commits/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-fsync-pressure-slow-commits/</guid><description>&lt;h1 id="mysql-slow-commits-with-idle-cpu-redo-and-binlog-fsync-pressure">MySQL slow commits with idle CPU: redo and binlog fsync pressure&lt;/h1>
&lt;p>Slow commits or transaction timeouts with idle CPU usually mean the bottleneck is in the durability path, not the query engine.&lt;/p>
&lt;p>With &lt;code>innodb_flush_log_at_trx_commit=1&lt;/code> and &lt;code>sync_binlog=1&lt;/code>, every &lt;code>COMMIT&lt;/code> triggers an InnoDB redo log &lt;code>fsync()&lt;/code> and a binary log &lt;code>fsync()&lt;/code> before returning to the client. These are sequential, latency-bound operations. When storage cannot drain fsync requests as fast as the server generates them, commits queue up while the CPU waits.&lt;/p></description></item><item><title>MySQL slow queries: from Slow_queries to the slow log to the fix</title><link>https://www.netdata.cloud/guides/mysql/mysql-slow-queries-diagnosis/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-slow-queries-diagnosis/</guid><description>&lt;h1 id="mysql-slow-queries-from-slow_queries-to-the-slow-log-to-the-fix">MySQL slow queries: from Slow_queries to the slow log to the fix&lt;/h1>
&lt;p>When &lt;code>Slow_queries&lt;/code> climbs but the slow log is empty, or &lt;code>long_query_time&lt;/code> is still at the default 10 seconds, you have an instrumentation gap. &lt;code>Slow_queries&lt;/code> increments regardless of whether &lt;code>slow_query_log&lt;/code> is &lt;code>ON&lt;/code>, so a rising counter with no log detail is a dead end.&lt;/p>
&lt;p>This guide moves from the status counter to slow log configuration, then to &lt;code>performance_schema&lt;/code> digests, and finally to resource signals that explain why queries slowed. The goal is to help you decide in minutes whether you face a query plan regression, lock contention, buffer pool pressure, or a configuration gap.&lt;/p></description></item><item><title>MySQL Sort_merge_passes climbing: filesort and sort_buffer_size</title><link>https://www.netdata.cloud/guides/mysql/mysql-filesort-sort-merge-passes/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-filesort-sort-merge-passes/</guid><description>&lt;h1 id="mysql-sort_merge_passes-climbing-filesort-and-sort_buffer_size">MySQL Sort_merge_passes climbing: filesort and sort_buffer_size&lt;/h1>
&lt;p>&lt;code>Sort_merge_passes&lt;/code> climbing fast is the signature of filesort spilling to disk. You notice it in &lt;code>SHOW GLOBAL STATUS&lt;/code>, along with rising disk I/O on the tmpdir partition and a growing &lt;code>Handler_read_rnd&lt;/code>. Queries that returned in milliseconds now take seconds.&lt;/p>
&lt;p>The absolute value of this cumulative counter is meaningless. Rate of change is what matters. A rapid climb within hours means sorts that used to stay in memory are now writing chunks to disk and merging them in multiple passes. Each pass costs disk I/O and adds latency. Active threads pile up behind slow sorts, driving &lt;code>Threads_running&lt;/code> higher and the &lt;code>Questions&lt;/code> rate lower.&lt;/p></description></item><item><title>MySQL stuck in InnoDB crash recovery: why startup hangs after an unclean shutdown</title><link>https://www.netdata.cloud/guides/mysql/mysql-crash-recovery-slow-startup/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-crash-recovery-slow-startup/</guid><description>&lt;h1 id="mysql-stuck-in-innodb-crash-recovery-why-startup-hangs-after-an-unclean-shutdown">MySQL stuck in InnoDB crash recovery: why startup hangs after an unclean shutdown&lt;/h1>
&lt;p>After an unclean shutdown, mysqld may look healthy: the process is running, port 3306 accepts connections, and &lt;code>SHOW GLOBAL STATUS LIKE 'Uptime'&lt;/code> counts up. Yet applications time out, &lt;code>SELECT 1&lt;/code> hangs, and the error log prints InnoDB recovery messages. InnoDB is replaying the redo log to make data files consistent, rolling back incomplete transactions, merging the change buffer, and running purge. Until that finishes, queries are rejected.&lt;/p></description></item><item><title>MySQL tablespace fragmentation: reclaiming space with OPTIMIZE TABLE</title><link>https://www.netdata.cloud/guides/mysql/mysql-tablespace-fragmentation-data-free/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-tablespace-fragmentation-data-free/</guid><description>&lt;h1 id="mysql-tablespace-fragmentation-reclaiming-space-with-optimize-table">MySQL tablespace fragmentation: reclaiming space with OPTIMIZE TABLE&lt;/h1>
&lt;p>InnoDB tablespaces fragment after bulk deletes, updates, and purge cycles. Logical data volume shrinks, but the on-disk file retains allocated extents because InnoDB returns freed pages to its internal free lists rather than the OS. For file-per-table &lt;code>.ibd&lt;/code> tables, that unused space is visible as &lt;code>DATA_FREE&lt;/code> in &lt;code>information_schema.TABLES&lt;/code> and can be reclaimed with &lt;code>OPTIMIZE TABLE&lt;/code>.&lt;/p>
&lt;p>Tables inside the shared system tablespace &lt;code>ibdata1&lt;/code> do not shrink at the OS level. Freed space returns to InnoDB&amp;rsquo;s internal free lists, but &lt;code>ibdata1&lt;/code> never releases extents back to the filesystem. If the goal is reclaiming disk space on a full volume, &lt;code>OPTIMIZE TABLE&lt;/code> against tables in &lt;code>ibdata1&lt;/code> is ineffective. The rest of this guide covers identifying reclaimable tables, running the rebuild safely, and verifying the result.&lt;/p></description></item><item><title>MySQL Threads_connected vs Threads_running: which one to actually alert on</title><link>https://www.netdata.cloud/guides/mysql/mysql-threads-connected-vs-threads-running/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-threads-connected-vs-threads-running/</guid><description>&lt;h1 id="mysql-threads_connected-vs-threads_running-which-one-to-actually-alert-on">MySQL Threads_connected vs Threads_running: which one to actually alert on&lt;/h1>
&lt;p>&lt;code>Threads_connected&lt;/code> counts every client holding an open socket, including idle pooled connections. &lt;code>Threads_running&lt;/code> counts only threads actively executing a statement. Paging on the first while ignoring the second is a common postmortem mistake. &lt;code>Threads_running&lt;/code> relative to CPU cores is the real load signal. The gap between the two metrics diagnoses failure modes. Connection count still deserves a ticket, but rarely a page.&lt;/p></description></item><item><title>MySQL Threads_created climbing: thread cache churn and missing pooling</title><link>https://www.netdata.cloud/guides/mysql/mysql-thread-cache-churn/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-thread-cache-churn/</guid><description>&lt;h1 id="mysql-threads_created-climbing-thread-cache-churn-and-missing-pooling">MySQL Threads_created climbing: thread cache churn and missing pooling&lt;/h1>
&lt;p>When the rate of &lt;code>Threads_created&lt;/code> climbs to tens or hundreds of new threads per minute, the thread cache is not absorbing your connection churn. In a pooled deployment this rate should stay near zero. Every cache miss pays the full cost of OS thread creation and initialization, plus a TLS handshake if &lt;code>require_secure_transport&lt;/code> is enabled. The first visible symptom is usually connection latency spikes or CPU time diverted to thread management.&lt;/p></description></item><item><title>MySQL TLS and encryption monitoring: unencrypted connections and weak auth plugins</title><link>https://www.netdata.cloud/guides/mysql/mysql-tls-encryption-monitoring/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-tls-encryption-monitoring/</guid><description>&lt;h1 id="mysql-tls-and-encryption-monitoring-unencrypted-connections-and-weak-auth-plugins">MySQL TLS and encryption monitoring: unencrypted connections and weak auth plugins&lt;/h1>
&lt;p>MySQL 8.0 generates self-signed certificates on startup and enables TLS by default, but this does not guarantee encrypted traffic. Clients must explicitly request TLS over TCP, and misconfigurations often leave sessions in plaintext without errors. Long-lived accounts frequently remain on &lt;code>mysql_native_password&lt;/code> despite its deprecation in MySQL 8.0.34, while &lt;code>caching_sha2_password&lt;/code> requires secure transport or RSA key exchange on first connection, causing sporadic authentication failures when client drivers lack encryption configuration. These risks are invisible to standard availability monitoring. This guide covers the status variables, Performance Schema tables, and account audits needed to detect unencrypted connections and weak authentication plugins in production.&lt;/p></description></item><item><title>MySQL undo tablespace growing: ibdata1 bloat and undo truncation</title><link>https://www.netdata.cloud/guides/mysql/mysql-undo-tablespace-growing/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-undo-tablespace-growing/</guid><description>&lt;h1 id="mysql-undo-tablespace-growing-ibdata1-bloat-and-undo-truncation">MySQL undo tablespace growing: ibdata1 bloat and undo truncation&lt;/h1>
&lt;p>Disk space alert: &lt;code>/var/lib/mysql/ibdata1&lt;/code> is 40 GB larger than last week, or the &lt;code>undo_*.ibu&lt;/code> files in MySQL 8.0 are consuming terabytes. Table sizes from &lt;code>information_schema&lt;/code> do not justify the growth. This is almost always undo log accumulation from a blocked purge thread.&lt;/p>
&lt;p>Undo logs let InnoDB reconstruct older row versions for MVCC and transaction rollback. The purge thread deletes them when no active transaction needs them. If one long-running transaction holds a read view, purge stops. History list length then grows linearly with write rate, and the undo tablespace expands to hold the backlog. In MySQL 5.7, that space lands in the system tablespace &lt;code>ibdata1&lt;/code>, which never shrinks. In MySQL 8.0, separate undo tablespaces can truncate automatically, but only after the history list drains and the purge thread frees rollback segments. Until then, the disk fills.&lt;/p></description></item><item><title>MySQL Waiting for table metadata lock: diagnosing the DDL stall</title><link>https://www.netdata.cloud/guides/mysql/mysql-waiting-for-table-metadata-lock/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-waiting-for-table-metadata-lock/</guid><description>&lt;h1 id="mysql-waiting-for-table-metadata-lock-diagnosing-the-ddl-stall">MySQL Waiting for table metadata lock: diagnosing the DDL stall&lt;/h1>
&lt;p>You run &lt;code>SHOW PROCESSLIST&lt;/code> and see a wall of threads in &lt;code>Waiting for table metadata lock&lt;/code>. An &lt;code>ALTER TABLE&lt;/code> that should finish in seconds hangs for minutes. Queries against one table stop returning, the application connection pool drains, and CPU and disk look calm. This is a metadata lock (MDL) stall. It is a queueing failure, not resource exhaustion. Left alone, it cascades into connection exhaustion and a partial outage where every other table continues to work normally.&lt;/p></description></item><item><title>MySQL: got a packet bigger than 'max_allowed_packet' bytes - causes and fixes</title><link>https://www.netdata.cloud/guides/mysql/mysql-max-allowed-packet-errors/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.netdata.cloud/guides/mysql/mysql-max-allowed-packet-errors/</guid><description>&lt;h1 id="mysql-got-a-packet-bigger-than-max_allowed_packet-bytes---causes-and-fixes">MySQL: got a packet bigger than &amp;lsquo;max_allowed_packet&amp;rsquo; bytes - causes and fixes&lt;/h1>
&lt;p>ER_NET_PACKET_TOO_LARGE (MySQL error 1153) drops the connection immediately. The payload crossed a limit on the client, the server, or a replica. A common mistake is tuning only the server: a source set to 256 MB still aborts a 20 MB payload if the &lt;code>mysql&lt;/code> client is at its default 16 MB. Replicas add their own hard and soft ceilings. This guide shows how to identify which boundary failed, raise it without a restart where possible, and prevent recurrence.&lt;/p></description></item></channel></rss>