<?xml version="1.0" encoding="utf-8" ?>
<rss version="2.0"
     xmlns:dc="http://purl.org/dc/elements/1.1/"
     xmlns:content="http://purl.org/rss/1.0/modules/content/">

<channel>
  <title>Planet MySQL</title>
  <link>https://planet.mysql.com</link>
  <pubDate>Sun, 17 May 2026 20:34:48 +0000</pubDate>
  <language>en</language>
  <description>Planet MySQL - https://planet.mysql.com</description>

  <item>
    <title>Building an AI Vision Search Engine with MySQL HeatWave GenAI</title>
    <guid isPermaLink="false">https://dasini.net/blog/?p=8533</guid>
    <link>https://dasini.net/blog/2026/05/14/building-an-ai-vision-search-engine-with-mysql-heatwave-genai/</link>
    <description>Modern AI systems increasingly rely on multimodal data: text, images, documents, audio, and video. Among these modalities, image understanding has become one of the most important capabilities for AI-powered applications.
Traditionally, implementing these capabilities required specialized computer vision infrastructure, external vector databases, custom ML pipelines, and multiple frameworks.
With MySQL HeatWave GenAI, many of these capabilities can now be implemented directly inside SQL workflows using built-in AI routines.
In this article, we will build the foundations of a Vision Model Evaluation Assistant using MySQL HeatWave GenAI. The objective is not to create another image classifier, but rather a semantic image understanding platform.
The post Building an AI Vision Search Engine with MySQL HeatWave GenAI first appeared on dasini.net - Diary of a MySQL expert.</description>
    <content:encoded><![CDATA[<p>Modern AI systems increasingly rely on multimodal data: text, images, documents, audio, and video. Among these modalities, image understanding has become one of the most important capabilities for AI-powered applications.<br>
Traditionally, implementing these capabilities required specialized computer vision infrastructure, external vector databases, custom ML pipelines, and multiple frameworks.<br>
With MySQL HeatWave GenAI, many of these capabilities can now be implemented directly inside SQL workflows using built-in AI routines.<br>
In this article, we will build the foundations of a Vision Model Evaluation Assistant using MySQL HeatWave GenAI. The objective is not to create another image classifier, but rather a semantic image understanding platform.</p>
The post <a href="https://dasini.net/blog/2026/05/14/building-an-ai-vision-search-engine-with-mysql-heatwave-genai/">Building an AI Vision Search Engine with MySQL HeatWave GenAI</a> first appeared on <a href="https://dasini.net/blog">dasini.net - Diary of a MySQL expert</a>.]]></content:encoded>
    <pubDate>Thu, 14 May 2026 16:54:52 +0000</pubDate>
    <dc:creator>Olivier Dasini</dc:creator>
    <category>AI</category>
    <category>Artificial Intelligence</category>
    <category>Cloud</category>
    <category>HeatWave</category>
    <category>Howto</category>
    <category>MDS</category>
    <category>MySQL</category>
    <category>Tuto</category>
    <category>GenAI</category>
    <category>Image</category>
    <category>tuto</category>
  </item>

  <item>
    <title>MySQL Community Update: Public Discussion #4, Design Proposals, and Contributor Summit</title>
    <guid isPermaLink="false">34db9b3cc46c77836ade0ab2348457fd</guid>
    <link>https://blogs.oracle.com/mysql/mysql-community-update-public-discussion-4-design-proposals-and-contributor-summit</link>
    <description>Following the strong engagement across the first three editions of our Public MySQL Community Discussion series, we’re pleased to invite you to Edition #4. We will focus on the upcoming contribution process changes and our Contributor Summit later in May. This ongoing series is part of our commitment to increase transparency, strengthen collaboration, and provide […]</description>
    <pubDate>Tue, 12 May 2026 15:20:34 +0000</pubDate>
    <dc:creator>Oracle MySQL Group</dc:creator>
    <category>MySQL</category>
    <category>MySQL Community</category>
  </item>

  <item>
    <title>MyVector v1.26.5: Component Architecture Arrives</title>
    <guid isPermaLink="false">http://askdba.net/?p=2949</guid>
    <link>https://askdba.net/2026/05/09/myvector-v1-26-5-component-architecture-arrives/</link>
    <description>MySQL 9.7 LTS Support Lands Released May 8, 2026 · GitHub Release



v1.26.5 introduces a MySQL Component build for MySQL 8.4 LTS and 9.7 LTS, a unified logging abstraction, and a set of plugin stability fixes. The plugin path for MySQL 8.0, 8.4, and 9.0 is unchanged.



Why the Component architecture matters



MySQL has been deprecating the legacy plugin API in favor of the Component architecture since 8.0. Components install via INSTALL COMPONENT, integrate through typed service interfaces, and are better isolated from server internals — meaning fewer breakages across MySQL minor versions and a supported path forward as the plugin API winds down. For MyVector, this move isn’t optional in the long run: the component model is where MySQL’s extension ecosystem is heading, and building on it now means users on 8.4 LTS and 9.7 LTS get a stable, upgrade-resilient foundation rather than a deprecated one.



What’s New



MySQL Component build. MyVector can now be installed via INSTALL COMPONENT on MySQL 8.4 and 9.7. The component ships UDF registration, binlog-driven index synchronization, and a query rewrite service hook — all backed by the same core vector index engine as the plugin. A new myvector_log.h abstraction unifies logging across both build modes, replacing scattered #ifdef blocks.



MySQL 9.7 LTS. The 9.x CI, release, and Docker targets move from 9.6 to 9.7 LTS. A new Docker image tag ghcr.io/askdba/myvector:mysql9.7 is now available. If you’re on :mysql9.6, switch to :mysql9.7.



Plugin stability fixes. gmtime() and asctime() replaced with their thread-safe _r variants; concurrency fixes in plugin init/deinit; null-guard added to myvector_ann_set row function. Also: config file permission hardening, a binary_log namespace conflict fix on 8.4/9.7, and a Quick Start wget URL correction (issue #89).



How to Install



Component — pre-built binaries (Linux amd64) are attached to this release:



bash



	
		
			

tar -xzf myvector-component-mysql8.4.8-linux-amd64.tar.gzcp libmyvector_component.so $(mysql_config --plugindir)/mysql -u root -p -e &quot;INSTALL COMPONENT 'file://libmyvector_component';&quot;
		
	



Also available: myvector-component-mysql9.7.0-linux-amd64.tar.gz and checksums.txt. To build from source, use scripts/build-component-8.4-docker.sh or scripts/build-component-9.7-docker.sh.



Plugin — Docker or build from source. Pre-built plugin .so files are not on the release page. Use Docker (multi-arch, amd64 + arm64):



bash



	
		
			

docker pull ghcr.io/askdba/myvector:mysql8.4   # or :mysql8.0, :mysql9.7
		
	



Or build from source with scripts/build-release.sh (requires MySQL dev headers).



Upgrade Notes




No schema or index migration required.



Docker tag change: :mysql9.6 → :mysql9.7.



The component path is the forward path for MySQL 8.4+. The plugin remains supported for 8.0/8.4/9.0 through their EOL dates.



Windows is not supported — use Linux container images.




See docs/BUILD_MODES.md and docs/COMPONENT_MIGRATION_PLAN.md for migration guidance. Bugs and feedback welcome on GitHub Issues.



</description>
    <content:encoded><![CDATA[<p class="wp-block-paragraph">MySQL 9.7 LTS Support Lands Released May 8, 2026 · <a href="https://github.com/askdba/myvector/releases/tag/v1.26.5">GitHub Release</a></p>



<p class="wp-block-paragraph">v1.26.5 introduces a MySQL <strong>Component</strong> build for MySQL 8.4 LTS and 9.7 LTS, a unified logging abstraction, and a set of plugin stability fixes. The plugin path for MySQL 8.0, 8.4, and 9.0 is unchanged.</p>



<h2 class="wp-block-heading">Why the Component architecture matters</h2>



<p class="wp-block-paragraph">MySQL has been deprecating the legacy plugin API in favor of the Component architecture since 8.0. Components install via <code>INSTALL COMPONENT</code>, integrate through typed service interfaces, and are better isolated from server internals — meaning fewer breakages across MySQL minor versions and a supported path forward as the plugin API winds down. For MyVector, this move isn’t optional in the long run: the component model is where MySQL’s extension ecosystem is heading, and building on it now means users on 8.4 LTS and 9.7 LTS get a stable, upgrade-resilient foundation rather than a deprecated one.</p>



<h2 class="wp-block-heading">What’s New</h2>



<p class="wp-block-paragraph"><strong>MySQL Component build.</strong> MyVector can now be installed via <code>INSTALL COMPONENT</code> on MySQL 8.4 and 9.7. The component ships UDF registration, binlog-driven index synchronization, and a query rewrite service hook — all backed by the same core vector index engine as the plugin. A new <code>myvector_log.h</code> abstraction unifies logging across both build modes, replacing scattered <code>#ifdef</code> blocks.</p>



<p class="wp-block-paragraph"><strong>MySQL 9.7 LTS.</strong> The 9.x CI, release, and Docker targets move from 9.6 to 9.7 LTS. A new Docker image tag <code>ghcr.io/askdba/myvector:mysql9.7</code> is now available. If you’re on <code>:mysql9.6</code>, switch to <code>:mysql9.7</code>.</p>



<p class="wp-block-paragraph"><strong>Plugin stability fixes.</strong> <code>gmtime()</code> and <code>asctime()</code> replaced with their thread-safe <code>_r</code> variants; concurrency fixes in plugin init/deinit; null-guard added to <code>myvector_ann_set</code> row function. Also: config file permission hardening, a <code>binary_log</code> namespace conflict fix on 8.4/9.7, and a Quick Start <code>wget</code> URL correction (issue #89).</p>



<h2 class="wp-block-heading">How to Install</h2>



<p class="wp-block-paragraph"><strong>Component — pre-built binaries (Linux amd64)</strong> are attached to this release:</p>



<p class="wp-block-paragraph">bash</p>


<div class="wp-block-code">
	<div class="cm-editor">
		<div class="cm-scroller">
			
<pre>
<code><div class="cm-line">tar -xzf myvector-component-mysql8.4.8-linux-amd64.tar.gz</div><div class="cm-line">cp libmyvector_component.so $(mysql_config --plugindir)/</div><div class="cm-line">mysql -u root -p -e "INSTALL COMPONENT 'file://libmyvector_component';"</div></code></pre>
		</div>
	</div>
</div>


<p class="wp-block-paragraph">Also available: <code>myvector-component-mysql9.7.0-linux-amd64.tar.gz</code> and <code>checksums.txt</code>. To build from source, use <code>scripts/build-component-8.4-docker.sh</code> or <code>scripts/build-component-9.7-docker.sh</code>.</p>



<p class="wp-block-paragraph"><strong>Plugin — Docker or build from source.</strong> Pre-built plugin <code>.so</code> files are not on the release page. Use Docker (multi-arch, amd64 + arm64):</p>



<p class="wp-block-paragraph">bash</p>


<div class="wp-block-code">
	<div class="cm-editor">
		<div class="cm-scroller">
			
<pre>
<code><div class="cm-line">docker pull ghcr.io/askdba/myvector:mysql8.4   # or :mysql8.0, :mysql9.7</div></code></pre>
		</div>
	</div>
</div>


<p class="wp-block-paragraph">Or build from source with <code>scripts/build-release.sh</code> (requires MySQL dev headers).</p>



<h2 class="wp-block-heading">Upgrade Notes</h2>



<ul class="wp-block-list">
<li>No schema or index migration required.</li>



<li>Docker tag change: <code>:mysql9.6</code> → <code>:mysql9.7</code>.</li>



<li>The component path is the forward path for MySQL 8.4+. The plugin remains supported for 8.0/8.4/9.0 through their EOL dates.</li>



<li>Windows is not supported — use Linux container images.</li>
</ul>



<p class="wp-block-paragraph">See <a href="https://github.com/askdba/myvector/blob/main/docs/BUILD_MODES.md"><code>docs/BUILD_MODES.md</code></a> and <a href="https://github.com/askdba/myvector/blob/main/docs/COMPONENT_MIGRATION_PLAN.md"><code>docs/COMPONENT_MIGRATION_PLAN.md</code></a> for migration guidance. Bugs and feedback welcome on <a href="https://github.com/askdba/myvector/issues">GitHub Issues</a>.</p>



<p class="wp-block-paragraph"></p>]]></content:encoded>
    <pubDate>Sat, 09 May 2026 08:08:19 +0000</pubDate>
    <dc:creator>Alkin Tezuysal</dc:creator>
    <category>mysql</category>
    <category>Technical</category>
    <category>ai</category>
    <category>artificial-intelligence</category>
    <category>coding</category>
    <category>llm</category>
    <category>technology</category>
  </item>

  <item>
    <title>A New Era of MySQL Monitoring: OpenTelemetry Metrics with Prometheus</title>
    <guid isPermaLink="false">7ff6317b92d59f67500cb49da31f962f</guid>
    <link>https://blogs.oracle.com/mysql/a-new-era-of-mysql-monitoring-opentelemetry-metrics-with-prometheus</link>
    <description>In modern application development, observability is no longer optional. It is a core requirement for stable operations, faster troubleshooting, and better understanding of system behavior. Databases are especially important because they often sit at the center of application performance. When a database becomes slow, overloaded, or unavailable, the impact is usually felt across the entire […]</description>
    <pubDate>Thu, 07 May 2026 01:58:47 +0000</pubDate>
    <dc:creator>Oracle MySQL Group</dc:creator>
    <category>Monitoring</category>
    <category>MySQL</category>
    <category>MySQL Community</category>
    <category>mysql</category>
    <category>mysqlcommunity</category>
  </item>

  <item>
    <title>MySQL 9.7 is out and the community wins </title>
    <guid isPermaLink="false">http://askdba.net/?p=2917</guid>
    <link>https://askdba.net/2026/05/06/mysql-9-7-is-out-and-the-community-wins/</link>
    <description>May 2026 · 5 min read. Alkin Tezuysal



Cross blog from Oracle https://blogs.oracle.com/mysql/mysql-9-7-is-out-and-the-community-wins



MySQL 9.7 came out on April 21 and I’ve been going through the release notes so you don’t have to. The short version: Oracle has made several previously Enterprise-only features available in the Community Edition; the Hypergraph Optimizer is now free for everyone; and if you’re still on MySQL 8.0, it has reached End-of-Life. Like right now. We’ll get to that.



Let’s go through what matters most.



First: MySQL 8.0 has reached End-of-Life



MySQL 8.0.46 shipped alongside 9.7, and it is the last 8.0 release. As of April 2026, 8.0 is officially End-of-Life. No more security patches. No more bug fixes. Oracle’s release notes now encourage users to upgrade to MySQL 8.4 LTS or 9.7.



If you’re on 8.0 in production, you’ve got two paths. MySQL 8.4 LTS is the safest, most conservative upgrade with a well-trodden migration path from 8.0. MySQL 9.7 is if you want all the new stuff, including everything in this post. Either way, the clock has run out on 8.0. It is strongly recommended to plan your upgrade soon.



Some Enterprise features available in the Community Edition



This is the headline. Oracle has moved five components from Enterprise Edition into Community Edition with this release. For self-hosted MySQL users, this is genuinely good news.



Four of them are replication components that now ship in Community Edition.



Replication Applier Metrics gives you real visibility into how your replica is processing events. Lag monitoring, throughput, the works. This was always the kind of thing you had to implement separately or access the Enterprise Edition.



Group Replication Flow Control Statistics now provides visibility into why your GR cluster is throttling. If you’ve ever stared at a slow cluster and had no idea what was happening under the hood, this one’s for you.



Group Replication Resource Manager lets you control how resources get allocated so replication stops starving your app workloads.



Group Replication Primary Election gives better observability into failover behavior during primary elections, which is exactly when you most need to know what’s going on.



And then there’s the Telemetry component, which is big if you’re running MySQL in a cloud-native setup. Metrics and traces can now flow to Prometheus, OpenTelemetry, and whatever else your observability stack includes. This was Enterprise-only until today.



The Hypergraph Optimizer is in Community Edition now



This is the one that stands out as particularly impactful.



Quick background: MySQL’s traditional query optimizer uses a left-deep tree approach to figure out join order. Works fine for simple queries, but with complex multi-table joins it can miss a lot of better execution plans. The Hypergraph Optimizer takes a completely different approach. It models the whole query as a hypergraph and uses dynamic programming to search a much bigger space of possible plans.



If you’ve got complex reporting queries or anything with a lot of joins, it’s worth turning on and seeing what happens.



To try it:



SET optimizer_switch=’hypergraph_optimizer=on’;



You can set it at session scope (great for testing), globally, persistently across restarts, or hint it on a per-query basis. Start with session scope on your actual slow queries before you go global. The optimizer is solid, but you don’t want surprises in production.



JSON Duality Views are now fully supported in Community



Previously, in Community Edition, you could define JSON Duality Views, but couldn’t do INSERTs, UPDATEs, or DELETEs through them. That was an Enterprise thing. This capability is now available in Community Edition. Full DML is now in Community.



They also added auto-increment support for duality view inserts, which means you can stop manually wiring up primary keys:



INSERT INTO orders_view



VALUES (‘{“customer_id”: 42, “product_id”: 7, “quantity”: 3}’);



The order_id gets generated automatically. Small change, but it removes a real friction point if you’ve been experimenting with duality views.



A few other things worth knowing



Password hashing got stronger.caching_sha2_password now supports PBKDF2 with SHA-512 storage format. Your existing clients don’t need to change anything since this is server-side only, but it makes stored hashes significantly harder to brute-force. Worth noting if you’re in a compliance-heavy environment like PCI-DSS or HIPAA.



Rolling upgrades just got easier. There’s a new variable called replica_allow_higher_version_source that lets a lower-version replica connect to a higher-version primary. Practically, this means you can upgrade your primary first, verify everything looks good, and then roll through your replicas at your own pace instead of taking the whole fleet down at once.



Container users, this one’s for you. MySQL now correctly reads cpuset cgroup limits to figure out how many CPUs are actually available to it. If you’d constrained MySQL to 4 CPUs in Kubernetes, it might have been sizing its thread pools against all 32 host CPUs anyway. That’s fixed.



OpenSSL got bumped to 3.5.5. Not exciting, but good hygiene.



What about Vector search?



A lot of people are asking about this, and the current status is that it is not yet generally available. Oracle is clearly building toward native vector search across the 9.x innovation releases, and you can see pieces of the foundation being put in place. But 9.7 isn’t the release where it lands as something you can use. It’s on the roadmap, it’s coming, the team is looking for feedback, and it is expected in future releases.  As some of you know, I’m especially interested in vector features as a maintainer of the MyVector project. We’ve had a couple of calls with the engineering team to collaborate on this subject. This might be an area for community contributions. Please stay tuned. 



So, should you upgrade?



Your situationWhat to doStill on MySQL 8.0Upgrade. It’s EOL. Pick 8.4 LTS or 9.7.On 8.4 LTS, happy where you areNothing urgent. Track 9.7 for the LTS landing.Running Group ReplicationTry the new components.Complex JOIN-heavy queriesBenchmark the Hypergraph Optimizer.Running MySQL in KubernetesThe cgroup CPU fix alone might be worth it.Excited about vector searchNot yet. Watch this space.



MySQL 9.7 is available at dev.mysql.com/downloads. If you end up benchmarking the Hypergraph Optimizer or trying the new replication components, share your results. The community learns from real-world numbers a lot more than from release notes. Drop them in the MySQL Community Forums or tag #MySQL97.</description>
    <content:encoded><![CDATA[<p class="wp-block-paragraph"><em>May 2026 · 5 min read. Alkin Tezuysal</em></p>



<p class="wp-block-paragraph">Cross blog from Oracle <a href="https://blogs.oracle.com/mysql/mysql-9-7-is-out-and-the-community-wins">https://blogs.oracle.com/mysql/mysql-9-7-is-out-and-the-community-wins</a></p>



<p class="wp-block-paragraph">MySQL 9.7 came out on April 21 and I’ve been going through the release notes so you don’t have to. The short version: Oracle has made several<strong> </strong>previously Enterprise-only features<strong> available</strong> in the Community Edition; the Hypergraph Optimizer is now free for everyone; and if you’re still on MySQL 8.0, it has reached End-of-Life. Like right now. We’ll get to that.</p>



<p class="wp-block-paragraph">Let’s go through what matters most.</p>



<p class="wp-block-paragraph"><strong>First: MySQL 8.0 has reached End-of-Life</strong></p>



<p class="wp-block-paragraph">MySQL 8.0.46 shipped alongside 9.7, and it is the last 8.0 release. As of April 2026, 8.0 is officially End-of-Life. No more security patches. No more bug fixes. Oracle’s release notes now encourage users to upgrade to MySQL 8.4 LTS or 9.7.</p>



<p class="wp-block-paragraph">If you’re on 8.0 in production, you’ve got two paths. MySQL 8.4 LTS is the safest, most conservative upgrade with a well-trodden migration path from 8.0. MySQL 9.7 is if you want all the new stuff, including everything in this post. Either way, the clock has run out on 8.0. It is strongly recommended to plan your upgrade soon.</p>



<p class="wp-block-paragraph"><strong>Some Enterprise features available in the Community Edition</strong></p>



<p class="wp-block-paragraph">This is the headline. Oracle has moved five components from Enterprise Edition into Community Edition with this release. For self-hosted MySQL users, this is genuinely good news.</p>



<p class="wp-block-paragraph">Four of them are replication components that now ship in Community Edition.</p>



<p class="wp-block-paragraph"><strong>Replication Applier Metrics</strong> gives you real visibility into how your replica is processing events. Lag monitoring, throughput, the works. This was always the kind of thing you had to implement separately or access the Enterprise Edition.</p>



<p class="wp-block-paragraph"><strong>Group Replication Flow Control Statistics</strong> now provides visibility into why your GR cluster is throttling<s>.</s> If you’ve ever stared at a slow cluster and had no idea what was happening under the hood, this one’s for you.</p>



<p class="wp-block-paragraph"><strong>Group Replication Resource Manager</strong> lets you control how resources get allocated so replication stops starving your app workloads.</p>



<p class="wp-block-paragraph"><strong>Group Replication Primary Election</strong> gives better observability into failover behavior during primary elections, which is exactly when you most need to know what’s going on.</p>



<p class="wp-block-paragraph">And then there’s the <strong>Telemetry component</strong>, which is big if you’re running MySQL in a cloud-native setup. Metrics and traces can now flow to Prometheus, OpenTelemetry, and whatever else your observability stack includes. This was Enterprise-only until today.</p>



<p class="wp-block-paragraph"><strong>The Hypergraph Optimizer is in Community Edition now</strong></p>



<p class="wp-block-paragraph">This is the one that stands out as particularly impactful.</p>



<p class="wp-block-paragraph">Quick background: MySQL’s traditional query optimizer uses a left-deep tree approach to figure out join order. Works fine for simple queries, but with complex multi-table joins it can miss a lot of better execution plans. The Hypergraph Optimizer takes a completely different approach. It models the whole query as a hypergraph and uses dynamic programming to search a much bigger space of possible plans.</p>



<p class="wp-block-paragraph">If you’ve got complex reporting queries or anything with a lot of joins, it’s worth turning on and seeing what happens.</p>



<p class="wp-block-paragraph">To try it:</p>



<p class="wp-block-paragraph">SET optimizer_switch=’hypergraph_optimizer=on’;</p>



<p class="wp-block-paragraph">You can set it at session scope (great for testing), globally, persistently across restarts, or hint it on a per-query basis. Start with session scope on your actual slow queries before you go global. The optimizer is solid, but you don’t want surprises in production.</p>



<p class="wp-block-paragraph"><strong>JSON Duality Views are now fully supported in Community</strong></p>



<p class="wp-block-paragraph">Previously, in Community Edition, you could <em>define</em> JSON Duality Views, but couldn’t do INSERTs, UPDATEs, or DELETEs through them. That was an Enterprise thing. This capability is now available in Community Edition.<strong> </strong>Full DML is now in Community.</p>



<p class="wp-block-paragraph">They also added auto-increment support for duality view inserts, which means you can stop manually wiring up primary keys:</p>



<p class="wp-block-paragraph">INSERT INTO orders_view</p>



<p class="wp-block-paragraph">VALUES (‘{“customer_id”: 42, “product_id”: 7, “quantity”: 3}’);</p>



<p class="wp-block-paragraph">The order_id gets generated automatically. Small change, but it removes a real friction point if you’ve been experimenting with duality views.</p>



<p class="wp-block-paragraph"><strong>A few other things worth knowing</strong></p>



<p class="wp-block-paragraph"><strong>Password hashing got stronger.</strong>caching_sha2_password now supports PBKDF2 with SHA-512 storage format. Your existing clients don’t need to change anything since this is server-side only, but it makes stored hashes significantly harder to brute-force. Worth noting if you’re in a compliance-heavy environment like PCI-DSS or HIPAA.</p>



<p class="wp-block-paragraph"><strong>Rolling upgrades just got easier.</strong> There’s a new variable called replica_allow_higher_version_source that lets a lower-version replica connect to a higher-version primary. Practically, this means you can upgrade your primary first, verify everything looks good, and then roll through your replicas at your own pace instead of taking the whole fleet down at once.</p>



<p class="wp-block-paragraph"><strong>Container users, this one’s for you.</strong> MySQL now correctly reads cpuset cgroup limits to figure out how many CPUs are actually available to it. If you’d constrained MySQL to 4 CPUs in Kubernetes, it might have been sizing its thread pools against all 32 host CPUs anyway. That’s fixed.</p>



<p class="wp-block-paragraph"><strong>OpenSSL got bumped to 3.5.5.</strong> Not exciting, but good hygiene.</p>



<p class="wp-block-paragraph"><strong>What about Vector search?</strong></p>



<p class="wp-block-paragraph">A lot of people are asking about this, and the current status is that it is not yet generally available. Oracle is clearly building toward native vector search across the 9.x innovation releases, and you can see pieces of the foundation being put in place. But 9.7 isn’t the release where it lands as something you can use. It’s on the roadmap, it’s coming, the team is looking for feedback, and it is expected in future releases.<strong> </strong> As some of you know, I’m especially interested in vector features as a maintainer of the <a href="https://github.com/askdba/myvector">MyVector</a> project. We’ve had a couple of calls with the engineering team to collaborate on this subject. This might be an area for community contributions. Please stay tuned. </p>



<p class="wp-block-paragraph"><strong>So, should you upgrade?</strong></p>



<figure class="wp-block-table"><table class="has-fixed-layout"><tbody><tr><td><strong>Your situation</strong></td><td><strong>What to do</strong></td></tr><tr><td>Still on MySQL 8.0</td><td>Upgrade. It’s EOL. Pick 8.4 LTS or 9.7.</td></tr><tr><td>On 8.4 LTS, happy where you are</td><td>Nothing urgent. Track 9.7 for the LTS landing.</td></tr><tr><td>Running Group Replication</td><td>Try the new components.</td></tr><tr><td>Complex JOIN-heavy queries</td><td>Benchmark the Hypergraph Optimizer.</td></tr><tr><td>Running MySQL in Kubernetes</td><td>The cgroup CPU fix alone might be worth it.</td></tr><tr><td>Excited about vector search</td><td>Not yet. Watch this space.</td></tr></tbody></table></figure>



<p class="wp-block-paragraph"><br>MySQL 9.7 is available at<a href="https://dev.mysql.com/downloads/mysql/"> dev.mysql.com/downloads</a>. If you end up benchmarking the Hypergraph Optimizer or trying the new replication components, share your results. The community learns from real-world numbers a lot more than from release notes. Drop them in the MySQL Community Forums or tag <strong>#MySQL97</strong>.</p>]]></content:encoded>
    <pubDate>Wed, 06 May 2026 11:37:26 +0000</pubDate>
    <dc:creator>Alkin Tezuysal</dc:creator>
    <category>mysql</category>
    <category>Technical</category>
    <category>ai</category>
    <category>artificial-intelligence</category>
    <category>cloud</category>
    <category>myvector</category>
    <category>sql</category>
    <category>technology</category>
    <category>vector</category>
  </item>

  <item>
    <title>MySQL 9.7 Is Out and the Community Wins</title>
    <guid isPermaLink="false">57fb0c3fd8250b5113adfd0d65398ab0</guid>
    <link>https://blogs.oracle.com/mysql/mysql-9-7-is-out-and-the-community-wins</link>
    <description>Alkin Tezuysal Director of Services at Altinity Inc. MySQL 9.7 came out on April 21 and I’ve been going through the release notes so you don’t have to. The short version: Oracle has made several previously Enterprise-only features available in the Community Edition, the Hypergraph Optimizer is now free for everyone, and if you’re still on MySQL 8.0, it […]</description>
    <pubDate>Wed, 06 May 2026 10:39:07 +0000</pubDate>
    <dc:creator>Oracle MySQL Group</dc:creator>
    <category>MySQL</category>
    <category>MySQL Community</category>
    <category>mysql</category>
    <category>mysqlcommunity</category>
  </item>

  <item>
    <title>Why Your Application Should Not Use One MySQL User for Everything</title>
    <guid isPermaLink="false">f06d124462bf3d337b6f880ee3f75be8</guid>
    <link>https://blogs.oracle.com/mysql/why-your-application-should-not-use-one-mysql-user-for-everything</link>
    <description>Many applications start with a simple database setup: create one MySQL user, give it access to the application schema, put the credentials in the app config, and move on. That may work at first, but it is not a good long-term security model. A better approach is to use separate MySQL users for separate application […]</description>
    <pubDate>Mon, 04 May 2026 20:48:06 +0000</pubDate>
    <dc:creator>Oracle MySQL Group</dc:creator>
    <category>HeatWave AI</category>
    <category>MySQL</category>
    <category>MySQL Basics/How-To</category>
    <category>MySQL Community</category>
    <category>MySQL Enterprise</category>
    <category>MySQL HeatWave</category>
  </item>

  <item>
    <title>Curious case of PXC node that refused to start due to SSL</title>
    <guid isPermaLink="false">https://www.percona.com/?p=43312</guid>
    <link>https://www.percona.com/blog/curious-case-of-pxc-node-that-refused-to-start-due-to-ssl/</link>
    <description>In this blog, I am going to share a real-world debugging case study where a routine Percona XtraDB Cluster node restart led to an unexpected failure. I will walk through what we observed, what we checked, and how we ultimately identified the root cause.
Let’s see how the maintenance goes. It was supposed to be a simple restart. The kind you’ve done a hundred times. You SSH in, run the maintenance, bring the node back up, and go grab a coffee. Except this time, the coffee went cold on the desk… because MySQL refused to start.
The Problem
The error log of Percona XtraDB Cluster (8.0) had the following information:2025-11-05T05:26:10.982984Z 0 [ERROR] [MY-000059]   [Server] SSL error: Unable to get certificate from '/var/lib/mysql/server-cert.pem'.
2025-11-05T05:26:10.983030Z 0 [Warning] [MY-013595] [Server] Failed to initialize TLS for channel: mysql_main. See below for the description of exact issue.
2025-11-05T05:26:10.983045Z 0 [Warning] [MY-010069] [Server] Failed to set up SSL because of the following SSL library error: Unable to get certificate
2025-11-05T05:26:10.983052Z 0 [Note] [MY-000000] [WSREP] New joining cluster node configured to use specified SSL artifacts
2025-11-05T05:26:10.983083Z 0 [Note] [MY-000000] [Galera] Loading provider /usr/lib64/galera4/libgalera_smm.so initial position: 07c67757-0d18-11ef-b5a9-ee5d87b39aa8:4147053897
2025-11-05T05:26:10.983098Z 0 [Note] [MY-000000] [Galera] wsrep_load(): loading provider library '/usr/lib64/galera4/libgalera_smm.so'
2025-11-05T05:26:10.983742Z 0 [Note] [MY-000000] [Galera] wsrep_load(): Galera 4.22(f6c0465) by Codership Oy &amp;lt;info@codership.com&amp;gt; (modified by Percona &amp;lt;https://percona.com/&amp;gt;) loaded successfully.
2025-11-05T05:26:10.983771Z 0 [Note] [MY-000000] [Galera] Resolved symbol 'wsrep_node_isolation_mode_set_v1'
2025-11-05T05:26:10.983784Z 0 [Note] [MY-000000] [Galera] Resolved symbol 'wsrep_certify_v1'
2025-11-05T05:26:10.983807Z 0 [Note] [MY-000000] [Galera] CRC-32C: using 64-bit x86 acceleration.
2025-11-05T05:26:10.983995Z 0 [Note] [MY-000000] [Galera] not using SSL compression
2025-11-05T05:26:10.984341Z 0 [ERROR] [MY-000000] [Galera] Bad value '/var/lib/mysql/server-cert.pem' for SSL parameter 'socket.ssl_cert': 336245135: 'error:140AB18F:SSL routines:SSL_CTX_use_certificate:ee key too small'
         at /mnt/jenkins/workspace/pxc80-autobuild-RELEASE/test/rpmbuild/BUILD/Percona-XtraDB-Cluster-8.0.42/percona-xtradb-cluster-galera/galerautils/src/gu_asio.cpp:ssl_prepare_context():471
2025-11-05T05:26:10.984401Z 0 [ERROR] [MY-000000] [Galera] Failed to create a new provider '/usr/lib64/galera4/libgalera_smm.so' with options 'gcache.size=1G;gcache.recover=yes;socket.ssl=yes;socket.ssl_ca=/data00/mysqldata/ca.pem;socket.ssl_cert=/data00/mysqldata/server-cert.pem;socket.ssl_key=/data00/mysqldata/server-key.pem;socket.ssl_key=/var/lib/mysql/server-key.pem;socket.ssl_ca=/var/lib/mysql/ca.pem;socket.ssl_cert=/var/lib/mysql/server-cert.pem': Failed to initialize wsrep provider
2025-11-05T05:26:10.984434Z 0 [ERROR] [MY-000000] [WSREP] Failed to load provider
2025-11-05T05:26:10.984448Z 0 [ERROR] [MY-010119] [Server] Aborting
2025-11-05T05:26:10.984602Z 0 [System] [MY-010910] [Server] /usr/sbin/mysqld: Shutdown complete (mysqld 8.0.42-33.1)  Percona XtraDB Cluster (GPL), Release rel33, Revision 6673f8e, WSREP version 26.1.4.3.
2025-11-05T05:26:10.985473Z 0 [ERROR] [MY-010065] [Server] Failed to shutdown components infrastructure. 
MySQL was down, and the maintenance clock was running. The certificate file sitting at /var/lib/mysql/server-cert.pem was the same file that had been working perfectly fine before the restart!!
From past history, it was known that the following commands were executed correctly on the same cluster nodeSET GLOBAL ssl_ca = '/var/lib/mysql/ca.pem';
  SET GLOBAL ssl_cert = '/var/lib/mysql/server-cert.pem';
  SET GLOBAL ssl_key = '/var/lib/mysql/server-key.pem';
  ALTER INSTANCE RELOAD TLS;Clients connected over TLS. Galera nodes communicated securely. There were zero complaints from the error log.
In other words, the SSL reload at runtime inherited the process environment that existed when MySQL originally booted. Everything was smooth, but after a restart? MySQL complains and declines to start. So what has changed?
Checking Usual Suspects
File permissions
We checked the PEM files. 
Ownership: mysql:mysql.
Permissions: 644 for the cert, 600 for the key. 
We compared them against the other Galera nodes, and they were identical. This didn’t look like a permissions problem.
Is SELinux to blame here?
SELinux has ruined enough DBA time that it is one of the top spots on such checklists – but it was permissive.$ getenforce
PermissiveThat means it was logging any security issues, but not blocking. And there were no AVC denials related to MySQL or the PEM files in /var/log/audit/audit.log or dmesg!
File corruption
Did the files get corrupted/replaced during or before the MySQL restart?$ openssl x509 -in /var/lib/mysql/server-cert.pem -noout -text
# Output looked perfectly valid when compared to the output from other nodes

$ openssl rsa -in /var/lib/mysql/server-key.pem -check
RSA key okThe files were fine. They parsed cleanly. OpenSSL could read them. So why couldn’t MySQL?
More Logs review
We scanned /var/log/messages and journalctl for anything unusual around the time of the restart. No disk errors. No OOM kills. No kernel panics. Nothing that screamed “I am the Dhurandhar that’s destroyed your node.” At this point, most of the usual suspects were guilt-free, staring at us, asking, “Who did it?”
The Clue
It is good to communicate with stakeholders, and we did – “Was there any recent change on your side?” to the client, and then uttered the golden words “Last week the crypto-policy was updated on all of the DB servers to comply with PCI.”
PCI &amp;gt; Crypto-policy – Let’s go and check it !!$ update-crypto-policies --show
FUTUREThe system was running RHEL’s FUTURE cryptographic policy.
For those unfamiliar (including me at the time), Red Hat Enterprise Linux (and its derivatives, such as Rocky, Alma, and Oracle Linux) ships with a system-wide cryptographic policy framework. It’s a centralized way to enforce minimum standards for TLS versions, cipher suites, key lengths, and signature algorithms across all applications on the system that include OpenSS and yes, anything that links against those libraries… like MySQL.
Here’s a table that shows information about the crypto-policy levels:



Policy
RSA Minimum
TLS Minimum
SHA-1 Signatures
Use Case


LEGACY
1024-bit
TLS 1.0
Allowed
Old systems compatibility


DEFAULT
2048-bit
TLS 1.2
Allowed
Standard operations


FUTURE
3072-bit
TLS 1.2
Blocked
Forward-looking hardening


FIPS
2048-bit
TLS 1.2
Blocked
FIPS 140 compliance



 
 
 
 
 
 
 
 
So FUTURE demands a 3072-bit RSA key; otherwise, it is blocked. What do we have?
$ openssl rsa -in server-key.pem -text -noout | head -1
RSA Private Key: (2048 bit, 2 primes)2048 bits! C’mon! And now I recall the error log again… The hint was there:error:140AB18F:SSL routines:SSL_CTX_use_certificate:ee key too smallNow we have our story straight.
On restart, our PXC cluster node started a new process linked against OpenSSL, which now enforced the FUTURE policy. OpenSSL looked at the 2048-bit RSA certificate and said: “Nope. Too small.”
Fixture
The quick fix here would be to adjust the policy to DEFAULT.sudo update-crypto-policies --set DEFAULTThis will accept the current SSLs, and the node will join the cluster readily.
Alternatively, to remain compliant and adhere to the security policy strictness, the fixture will be to

Generate new certificates
Deploy the keys/certs to all Galera nodes
Perform a rolling restart

 
Conclusion
This was a classic case of a problem hiding at the boundary between two domains, database administration and operating system security. The DBA saw valid certificates and correct MySQL configuration. The sysadmin saw a properly hardened system with a strong crypto policy. Neither was wrong. But the intersection of their two correct configurations produced a failure.
This incident reinforces the importance of cross-domain awareness, where resolving database issues sometimes requires understanding and challenging system-level security decisions.
 
 
 
 
The post Curious case of PXC node that refused to start due to SSL appeared first on Percona.</description>
    <content:encoded><![CDATA[<p><span>In this blog, I am going to share a real-world debugging case study where a routine Percona XtraDB Cluster node restart led to an unexpected failure. I will walk through what we observed, what we checked, and how we ultimately identified the root cause.</span></p>
<p><span>Let’s see how the maintenance goes. It was supposed to be a simple restart. </span><span>The kind you’ve done a hundred times. You SSH in, run the maintenance, bring the node back up, and go grab a coffee. Except this time, the coffee went cold on the desk… because MySQL refused to start.</span></p>
<h2><span>The Problem</span></h2>
<p><span>The error log of Percona XtraDB Cluster (8.0) had the following information:</span></p><pre class="urvanov-syntax-highlighter-plain-tag">2025-11-05T05:26:10.982984Z 0 [ERROR] [MY-000059]   [Server] SSL error: Unable to get certificate from '/var/lib/mysql/server-cert.pem'.
2025-11-05T05:26:10.983030Z 0 [Warning] [MY-013595] [Server] Failed to initialize TLS for channel: mysql_main. See below for the description of exact issue.
2025-11-05T05:26:10.983045Z 0 [Warning] [MY-010069] [Server] Failed to set up SSL because of the following SSL library error: Unable to get certificate
2025-11-05T05:26:10.983052Z 0 [Note] [MY-000000] [WSREP] New joining cluster node configured to use specified SSL artifacts
2025-11-05T05:26:10.983083Z 0 [Note] [MY-000000] [Galera] Loading provider /usr/lib64/galera4/libgalera_smm.so initial position: 07c67757-0d18-11ef-b5a9-ee5d87b39aa8:4147053897
2025-11-05T05:26:10.983098Z 0 [Note] [MY-000000] [Galera] wsrep_load(): loading provider library '/usr/lib64/galera4/libgalera_smm.so'
2025-11-05T05:26:10.983742Z 0 [Note] [MY-000000] [Galera] wsrep_load(): Galera 4.22(f6c0465) by Codership Oy &lt;info@codership.com&gt; (modified by Percona &lt;https://percona.com/&gt;) loaded successfully.
2025-11-05T05:26:10.983771Z 0 [Note] [MY-000000] [Galera] Resolved symbol 'wsrep_node_isolation_mode_set_v1'
2025-11-05T05:26:10.983784Z 0 [Note] [MY-000000] [Galera] Resolved symbol 'wsrep_certify_v1'
2025-11-05T05:26:10.983807Z 0 [Note] [MY-000000] [Galera] CRC-32C: using 64-bit x86 acceleration.
2025-11-05T05:26:10.983995Z 0 [Note] [MY-000000] [Galera] not using SSL compression
2025-11-05T05:26:10.984341Z 0 [ERROR] [MY-000000] [Galera] Bad value '/var/lib/mysql/server-cert.pem' for SSL parameter 'socket.ssl_cert': 336245135: 'error:140AB18F:SSL routines:SSL_CTX_use_certificate:ee key too small'
         at /mnt/jenkins/workspace/pxc80-autobuild-RELEASE/test/rpmbuild/BUILD/Percona-XtraDB-Cluster-8.0.42/percona-xtradb-cluster-galera/galerautils/src/gu_asio.cpp:ssl_prepare_context():471
2025-11-05T05:26:10.984401Z 0 [ERROR] [MY-000000] [Galera] Failed to create a new provider '/usr/lib64/galera4/libgalera_smm.so' with options 'gcache.size=1G;gcache.recover=yes;socket.ssl=yes;socket.ssl_ca=/data00/mysqldata/ca.pem;socket.ssl_cert=/data00/mysqldata/server-cert.pem;socket.ssl_key=/data00/mysqldata/server-key.pem;socket.ssl_key=/var/lib/mysql/server-key.pem;socket.ssl_ca=/var/lib/mysql/ca.pem;socket.ssl_cert=/var/lib/mysql/server-cert.pem': Failed to initialize wsrep provider
2025-11-05T05:26:10.984434Z 0 [ERROR] [MY-000000] [WSREP] Failed to load provider
2025-11-05T05:26:10.984448Z 0 [ERROR] [MY-010119] [Server] Aborting
2025-11-05T05:26:10.984602Z 0 [System] [MY-010910] [Server] /usr/sbin/mysqld: Shutdown complete (mysqld 8.0.42-33.1)  Percona XtraDB Cluster (GPL), Release rel33, Revision 6673f8e, WSREP version 26.1.4.3.
2025-11-05T05:26:10.985473Z 0 [ERROR] [MY-010065] [Server] Failed to shutdown components infrastructure.</pre><p> </p>
<p><span>MySQL was down, and the maintenance clock was running. The certificate file sitting at <code>/var/lib/mysql/server-cert.pem</code> was the same file that had been working perfectly fine before the restart!!<br>
</span><span>From past history, it was known that the following commands were executed correctly on the same cluster node</span></p><pre class="urvanov-syntax-highlighter-plain-tag">SET GLOBAL ssl_ca = '/var/lib/mysql/ca.pem';
  SET GLOBAL ssl_cert = '/var/lib/mysql/server-cert.pem';
  SET GLOBAL ssl_key = '/var/lib/mysql/server-key.pem';
  ALTER INSTANCE RELOAD TLS;</pre><p><span>Clients connected over TLS. Galera nodes communicated securely. There were zero complaints from the error log.<br>
</span><span>In other words, the SSL reload at runtime inherited the process environment that existed when MySQL originally booted. Everything was smooth, but after a restart? MySQL complains and declines to start. So what has changed?</span></p>
<h2><span>Checking Usual Suspects</span></h2>
<p><b>File permissions</b></p>
<p><span>We checked the PEM files. </span></p>
<p><span>Ownership: <code>mysql:mysql</code>.<br>
</span><span>Permissions: <code>644</code> for the cert, <code>600</code> for the key. </span></p>
<p><span>We compared them against the other Galera nodes, and they were identical. This didn’t look like a permissions problem.</span></p>
<p><b>Is SELinux to blame here?</b></p>
<p><span>SELinux has ruined enough DBA time that it is one of the top spots on such checklists – but it was permissive.</span></p><pre class="urvanov-syntax-highlighter-plain-tag">$ getenforce
<span>Permissive</span></pre><p><span>That means it was logging any security issues, but not blocking. And there were no AVC denials related to MySQL or the PEM files in /var/log/audit/audit.log or dmesg!</span></p>
<p><b>File corruption</b></p>
<p><span>Did the files get corrupted/replaced during or before the MySQL restart?</span></p><pre class="urvanov-syntax-highlighter-plain-tag">$ openssl x509 -in /var/lib/mysql/server-cert.pem -noout -text
# Output looked perfectly valid when compared to the output from other nodes

$ openssl rsa -in /var/lib/mysql/server-key.pem -check
RSA key ok</pre><p><span>The files were fine. They parsed cleanly. OpenSSL could read them. So why couldn’t MySQL?</span></p>
<p><b>More Logs review</b></p>
<p><span>We scanned /var/log/messages and journalctl for anything unusual around the time of the restart. No disk errors. No OOM kills. No kernel panics. Nothing that screamed “I am the Dhurandhar that’s destroyed your node.” </span><span>At this point, most of the usual suspects were guilt-free, staring at us, asking, “Who did it?”</span></p>
<h2><span>The Clue</span></h2>
<p><span>It is good to communicate with stakeholders, and we did – “Was there any recent change on your side?” to the client, and then uttered the golden words “Last week the crypto-policy was updated on all of the DB servers to comply with PCI.”</span></p>
<p><span>PCI &gt; Crypto-policy – Let’s go and check it !!</span></p><pre class="urvanov-syntax-highlighter-plain-tag">$ update-crypto-policies --show
FUTURE</pre><p><span>The system was running RHEL’s FUTURE cryptographic policy.</span></p>
<p><span>For those unfamiliar (including me at the time), Red Hat Enterprise Linux (and its derivatives, such as Rocky, Alma, and Oracle Linux) ships with a system-wide cryptographic policy framework. It’s a centralized way to enforce minimum standards for TLS versions, cipher suites, key lengths, and signature algorithms across all applications on the system that include OpenSS and yes, anything that links against those libraries… like MySQL.</span></p>
<p>Here’s a table that shows information about the crypto-policy levels:</p>
<table class="alignleft" border="1">
<tbody>
<tr>
<td><span>Policy</span></td>
<td><span>RSA Minimum</span></td>
<td><span>TLS Minimum</span></td>
<td><span>SHA-1 Signatures</span></td>
<td><span>Use Case</span></td>
</tr>
<tr>
<td><span>LEGACY</span></td>
<td><span>1024-bit</span></td>
<td><span>TLS 1.0</span></td>
<td><span>Allowed</span></td>
<td><span>Old systems compatibility</span></td>
</tr>
<tr>
<td><span>DEFAULT</span></td>
<td><span>2048-bit</span></td>
<td><span>TLS 1.2</span></td>
<td><span>Allowed</span></td>
<td><span>Standard operations</span></td>
</tr>
<tr>
<td><span>FUTURE</span></td>
<td><span>3072-bit</span></td>
<td><span>TLS 1.2</span></td>
<td><span>Blocked</span></td>
<td><span>Forward-looking hardening</span></td>
</tr>
<tr>
<td><span>FIPS</span></td>
<td><span>2048-bit</span></td>
<td><span>TLS 1.2</span></td>
<td><span>Blocked</span></td>
<td><span>FIPS 140 compliance</span></td>
</tr>
</tbody>
</table>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<p><span>So FUTURE demands a 3072-bit RSA key; otherwise, it is blocked. What do we have?</span><span><br>
</span></p><pre class="urvanov-syntax-highlighter-plain-tag">$ openssl rsa -in server-key.pem -text -noout | head -1
RSA Private Key: (2048 bit, 2 primes)</pre><p><span>2048 bits! C’mon! And now I recall the error log again… The hint was there:</span></p><pre class="urvanov-syntax-highlighter-plain-tag">error:140AB18F:SSL routines:SSL_CTX_use_certificate:ee key too small</pre><p><span>Now we have our story straight.<br>
</span><span>On restart, our PXC cluster node started a new process linked against OpenSSL, which now enforced the FUTURE policy. OpenSSL looked at the 2048-bit RSA certificate and said: “Nope. Too small.”</span></p>
<h2><span>Fixture</span></h2>
<p><span>The quick fix here would be to adjust the policy to DEFAULT.</span></p><pre class="urvanov-syntax-highlighter-plain-tag">sudo update-crypto-policies --set DEFAULT</pre><p><span>This will accept the current SSLs, and the node will join the cluster readily.</span></p>
<p><span>Alternatively, to remain compliant and adhere to the security policy strictness, the fixture will be to</span></p>
<ul>
<li aria-level="1"><span>Generate new certificates</span></li>
<li aria-level="1"><span>Deploy the keys/certs to all Galera nodes</span></li>
<li aria-level="1"><span>Perform a rolling restart</span></li>
</ul>
<p> </p>
<h2><span>Conclusion</span></h2>
<p><span>This was a classic case of a problem hiding at the boundary between two domains, database administration and operating system security. The DBA saw valid certificates and correct MySQL configuration. The sysadmin saw a properly hardened system with a strong crypto policy. Neither was wrong. But the intersection of their two correct configurations produced a failure.</span></p>
<p><span>This incident reinforces the importance of cross-domain awareness, where resolving database issues sometimes requires understanding and challenging system-level security decisions.</span></p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<p>The post <a href="https://www.percona.com/blog/curious-case-of-pxc-node-that-refused-to-start-due-to-ssl/">Curious case of PXC node that refused to start due to SSL</a> appeared first on <a href="https://www.percona.com/">Percona</a>.</p>]]></content:encoded>
    <pubDate>Mon, 04 May 2026 05:45:15 +0000</pubDate>
    <dc:creator>Kedar Vaijanapurkar</dc:creator>
    <category>Insight for DBAs</category>
    <category>MySQL</category>
    <category>database troubleshooting case study</category>
    <category>FUTURE crypto policy</category>
    <category>Galera cluster failure</category>
    <category>Linux security policy</category>
    <category>MySQL Galera SSL</category>
    <category>MySQL SSL error</category>
    <category>OpenSSL error debugging</category>
    <category>OpenSSL policy impact</category>
    <category>Percona XtraDB Cluster</category>
    <category>PXC troubleshooting</category>
    <category>RSA key </category>
  </item>

  <item>
    <title>Building Query Analysis and Insights Dashboard in PMM</title>
    <guid isPermaLink="false">https://www.percona.com/?p=43348</guid>
    <link>https://www.percona.com/blog/building-query-analysis-and-insights-dashboard-in-pmm/</link>
    <description>Percona Monitoring and Management is a great open source database monitoring, observability, and management tool. Query analytics is one of the prominent features DBA uses actively to trace the incidents and query performance identification.
We all know and love the Query Analytics (QAN) dashboard… It’s the first place we look when an incident alert fires or when a developer asks, “Why is the app slow?” or “What was going on during the midnight production outage?”
But sometimes, the standard dashboards just don’t tell the whole story or maybe are not clear enough. QAN is great, but shouldn’t we have more? If you have PMM running, you already have a Ferrari engine under the hood: ClickHouse. Most of us just drive it in first gear using the default UI.
In this post, we are going to take the training wheels off. We will bypass the standard QAN interface and talk directly to the ClickHouse backend to build highly specialised dashboards. We aren’t just looking for “slow” queries anymore; we are hunting for inefficiency, volatility, and the “silent killers” that standard monitoring often misses.
This is the hands-on blog, so grab your coffee and let’s turn that PMM instance into a deep-dive forensic tool.
Create a New Dashboard in PMM

Connect to PMM &amp;gt; Dashboards &amp;gt; Create New Dashboard
Save it with name “Slow Query Analysis” and Description “Slow Query Analysis from PMM’s QAN database (clickhouse)”
Click on add visualisation &amp;amp; select datasource “ClickHouse”


Choose SQL Builder


Paste the following query to get top 10 slow queries from the database

SELECT fingerprint
    FROM pmm.metrics
    WHERE service_type = 'mysql'
      AND $__timeFilter(period_start)
    GROUP BY fingerprint
    ORDER BY sum(m_query_time_sum) DESC
    LIMIT 10

Choose “Table View” on the top to view the list
When you click “Run Query” you will see the top 10 slow queries in the chosen time period.
Let’s Save the dashboard after Panel Options updates as follows7.1 Change Panel Name and Description to: “Slow Query Analysis”7.2 Legend Placement to “Bottom”, Values to “min”,”max”, “mean”7.3 Change Axis’ Scale to “Logarithmic”Logarithmic scale on an axis compresses large ranges of data, making it ideal for visualizing metrics with vastly different magnitudes. This provides good visualisation for queries of different execution time frames.7.4 Save DashboardAlright, we’re at our first step. This first result set shows the top 10 slow query fingerprints across all MySQL services tracked by PMM for the selected time range. It provides a quick, environment-wide view of the most expensive query patterns. But this does not provide a clear picture. Let’s refine the dashboard to focus on specific queries, servers and observe their performance over time.Now, let’s introduce a variable to filter the data.
Click on Settings on Dashboard’s home page8.1 Choose “Variables” tab and click on “Add Variable”8.2 Add variable configuration and Save Dashboard 
Go Back to Dashboard and Edit “Slow Query Analysis” Panel.

Now you should see the Query ID filter on the top.


Change the query to the following

SELECT
  period_start AS time,
  left(fingerprint, 80) AS query_text,
  sum(m_query_time_sum/m_query_time_cnt) AS query_time
FROM
  pmm.metrics
WHERE
  service_type = 'mysql'
  AND $__timeFilter(period_start)
  AND fingerprint IN (
    SELECT fingerprint
    FROM pmm.metrics
    WHERE service_type = 'mysql'
      AND $__timeFilter(period_start)
      AND ($queryid = '' OR queryid = $queryid)
    GROUP BY fingerprint
    ORDER BY sum(m_query_time_sum) DESC
    LIMIT 10
  )
GROUP BY
  time,
  fingerprint
ORDER BY
  time,
  query_time DESC

Basically the query is fetching start time, query text and average query time for the selected period for the top 10 Queries in that time-frame.
There is a filter for the “queryid” variable which you may use if you want to filter on a specific queryid.
Choose “Time Series” as “Query Type”


Adjust Panel Options11.1 Choose “Standard options” &amp;gt; “Unit” as “Time / Seconds (s)” from drop down.11.2 Choose “Standard options” &amp;gt; “Display name” as “${__field.labels.query_text}”11.3 Click on “Save Dashboard”
 Your dashboard should be ready

Now, by default this dashboard is plotting top 10 queries. If you have a query fingerprint handy, you may be able to filter the search by that specific query.  That said, this is still plotting queries across all the monitored instances. Let’s move on to add the service_name filter.
 
Adding service_name filter

Add Variable

Create new variable named “service_name”
Use variable type “Query”
Use Data Source as “ClickHouse”
Query:

select distinct service_name from pmm.metrics where service_type = 'mysql';

Unselect all checkboxes in “Selection options”
Save Dashboard


Update Query

SELECT
  period_start AS time,
  left(fingerprint, 80) AS query_text,
  sum(m_query_time_sum/m_query_time_cnt) AS query_time
FROM
  pmm.metrics
WHERE
  (service_name = '' OR service_name = '$service_name')
  AND service_type = 'mysql'
  AND $__timeFilter(period_start)
  AND fingerprint IN (
    SELECT fingerprint
    FROM pmm.metrics
    WHERE service_type = 'mysql'
      AND $__timeFilter(period_start)
      AND (service_name = '' OR service_name = '$service_name')
    GROUP BY fingerprint
    ORDER BY sum(m_query_time_sum) DESC
    LIMIT 10
  )
GROUP BY
  time,
  left(fingerprint, 80) 
ORDER BY
  time,
  query_time DESCI know many of you are naturally curious and enjoy experimenting with PMM and Grafana… So you’ve probably already started thinking about how far this can be taken. Feel free to share your ideas or custom dashboards in the comments.
Sample Dashboards:
 
The Query Analysis and Insights Dashboard
Okay, for those who are looking to have quick results, I’ve prepared the complete Query Analysis and Insights Dashboard for you to import and use instantly.
By importing the JSON file, you’ll get the full working dashboard with all panels preconfigured, including:

Slow Query Analysis
Latency Distribution Heatmap
Query Volatility (P99 vs Average)
Lock Wait Ratio Over Time (Top Contended Queries)
Temporary Table Usage (Disk &amp;amp; Memory)
Query Efficiency (Rows Examined vs Rows Sent)
Error Rate vs Throughput
Workload Distribution by User
Query Volume by Client Host
Execution Time vs Lock Wait Time

This allows you to instantly explore PMM Query Analytics data, adjust time ranges and filters, and correlate query performance, contention, and workload behavior without recreating the dashboard from scratch.
Dashboard JSON available here:

Grafana: https://grafana.com/grafana/dashboards/24896
GitHub:  https://github.com/Percona-Lab/pmm-dashboards/query_analysis_insights.json

Give it a go and let me know if you have suggestions or requests. Also consider sharing if you create something interesting.
Cheers.
The post Building Query Analysis and Insights Dashboard in PMM appeared first on Percona.</description>
    <content:encoded><![CDATA[<p><span>Percona Monitoring and Management is a great open source database monitoring, observability, and management tool. Query analytics is one of the prominent features DBA uses actively to trace the incidents and query performance identification.</span></p>
<p><span>We all know and love the Query Analytics (QAN) dashboard… It’s the first place we look when an incident alert fires or when a developer asks, </span><i><span>“Why is the app slow?” or “What was going on during the midnight production outage?”</span></i></p>
<p><span>But sometimes, the standard dashboards just don’t tell the whole story or maybe are not clear enough. QAN is great, but shouldn’t we have more? If you have PMM running, you already have a Ferrari engine under the hood: ClickHouse. Most of us just drive it in first gear using the default UI.</span></p>
<p><span>In this post, we are going to take the training wheels off. We will bypass the standard QAN interface and talk directly to the ClickHouse backend to build highly specialised dashboards. We aren’t just looking for “slow” queries anymore; we are hunting for inefficiency, volatility, and the “silent killers” that standard monitoring often misses.</span></p>
<p><span>This is the hands-on blog, so grab your coffee and let’s turn that PMM instance into a deep-dive forensic tool.</span></p>
<p><strong>Create a New Dashboard in PMM</strong></p>
<ol>
<li aria-level="1"><span>Connect to PMM &gt; Dashboards &gt; Create New Dashboard<img decoding="async" class="alignnone wp-image-43360" src="https://www.percona.com/wp-content/uploads/2026/04/pmm-new-dashboard.png" alt="" width="172" height="160" srcset="https://www.percona.com/wp-content/uploads/2026/04/pmm-new-dashboard.png 338w, https://www.percona.com/wp-content/uploads/2026/04/pmm-new-dashboard-300x279.png 300w" sizes="(max-width: 172px) 100vw, 172px"></span></li>
<li aria-level="1"><span>Save it with name “Slow Query Analysis” and Description “Slow Query Analysis from PMM’s QAN database (clickhouse)”</span><img fetchpriority="high" decoding="async" class="alignnone wp-image-43359" src="https://www.percona.com/wp-content/uploads/2026/04/pmm-save-dashboard.png" alt="" width="681" height="258" srcset="https://www.percona.com/wp-content/uploads/2026/04/pmm-save-dashboard.png 958w, https://www.percona.com/wp-content/uploads/2026/04/pmm-save-dashboard-300x114.png 300w, https://www.percona.com/wp-content/uploads/2026/04/pmm-save-dashboard-768x291.png 768w" sizes="(max-width: 681px) 100vw, 681px"></li>
<li aria-level="1"><span>Click on add visualisation &amp; select datasource “ClickHouse”<br>
<img decoding="async" class="alignnone size-full wp-image-43358" src="https://www.percona.com/wp-content/uploads/2026/04/pmm-data-source.png" alt="" width="537" height="368" srcset="https://www.percona.com/wp-content/uploads/2026/04/pmm-data-source.png 537w, https://www.percona.com/wp-content/uploads/2026/04/pmm-data-source-300x206.png 300w" sizes="(max-width: 537px) 100vw, 537px"><br>
</span></li>
<li aria-level="1"><span>Choose SQL Builder<br>
<img loading="lazy" decoding="async" class="alignnone size-full wp-image-43357" src="https://www.percona.com/wp-content/uploads/2026/04/pmm-sql-builder-1024x574-1.png" alt="" width="1024" height="574" srcset="https://www.percona.com/wp-content/uploads/2026/04/pmm-sql-builder-1024x574-1.png 1024w, https://www.percona.com/wp-content/uploads/2026/04/pmm-sql-builder-1024x574-1-300x168.png 300w, https://www.percona.com/wp-content/uploads/2026/04/pmm-sql-builder-1024x574-1-768x431.png 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px"><br>
</span></li>
<li aria-level="1"><span>Paste the following query to get top 10 slow queries from the database<br>
</span><br>
<pre class="urvanov-syntax-highlighter-plain-tag">SELECT fingerprint
    FROM pmm.metrics
    WHERE service_type = 'mysql'
      AND $__timeFilter(period_start)
    GROUP BY fingerprint
    ORDER BY sum(m_query_time_sum) DESC
    LIMIT 10</pre>
</li>
<li aria-level="1"><span>Choose “Table View” on the top to view the list<br>
</span><span>When you click “Run Query” you will see the top 10 slow queries in the chosen time period.<img loading="lazy" decoding="async" class="alignnone size-full wp-image-43356" src="https://www.percona.com/wp-content/uploads/2026/04/pmm-table-view-1024x557-1.png" alt="" width="1024" height="557" srcset="https://www.percona.com/wp-content/uploads/2026/04/pmm-table-view-1024x557-1.png 1024w, https://www.percona.com/wp-content/uploads/2026/04/pmm-table-view-1024x557-1-300x163.png 300w, https://www.percona.com/wp-content/uploads/2026/04/pmm-table-view-1024x557-1-768x418.png 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px"></span></li>
<li aria-level="1"><span>Let’s Save the dashboard after Panel Options updates as follows</span><span>7.1 Change Panel Name and Description to: “Slow Query Analysis”</span><span>7.2 Legend Placement to “Bottom”, Values to “min”,”max”, “mean”</span><span>7.3 Change Axis’ Scale to “Logarithmic”</span><i><span>Logarithmic scale on an axis compresses large ranges of data, making it ideal for visualizing metrics with vastly different magnitudes. This provides good visualisation for queries of different execution time frames.</span></i><span>7.4 Save Dashboard<img loading="lazy" decoding="async" class="alignnone size-full wp-image-43355" src="https://www.percona.com/wp-content/uploads/2026/04/pmm-dashboard-config.png" alt="" width="401" height="829" srcset="https://www.percona.com/wp-content/uploads/2026/04/pmm-dashboard-config.png 401w, https://www.percona.com/wp-content/uploads/2026/04/pmm-dashboard-config-145x300.png 145w" sizes="auto, (max-width: 401px) 100vw, 401px"></span><span>Alright, we’re at our first step. This first result set shows the </span><b>top 10 slow query fingerprints across all MySQL services tracked by PMM</b><span> for the selected time range. It provides a quick, environment-wide view of the most expensive query patterns. But this does not provide a clear picture. Let’s refine the dashboard to focus on specific queries, servers and observe their performance over time.</span><span>Now, let’s introduce a variable to filter the data.</span></li>
<li aria-level="1"><span>Click on </span><b>Settings</b><span> on Dashboard’s home page</span><img loading="lazy" decoding="async" class="alignnone size-full wp-image-43354" src="https://www.percona.com/wp-content/uploads/2026/04/pmm-dashboard-settings.png" alt="" width="634" height="401" srcset="https://www.percona.com/wp-content/uploads/2026/04/pmm-dashboard-settings.png 634w, https://www.percona.com/wp-content/uploads/2026/04/pmm-dashboard-settings-300x190.png 300w" sizes="auto, (max-width: 634px) 100vw, 634px">8.1 Choose “Variables” tab and click on “Add Variable”<img loading="lazy" decoding="async" class="alignnone size-full wp-image-43353" src="https://www.percona.com/wp-content/uploads/2026/04/pmm-add-variables-1024x917-1.png" alt="" width="1024" height="917" srcset="https://www.percona.com/wp-content/uploads/2026/04/pmm-add-variables-1024x917-1.png 1024w, https://www.percona.com/wp-content/uploads/2026/04/pmm-add-variables-1024x917-1-300x269.png 300w, https://www.percona.com/wp-content/uploads/2026/04/pmm-add-variables-1024x917-1-768x688.png 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px">8.2 Add variable configuration and Save Dashboard </li>
<li aria-level="1"><span>Go Back to Dashboard and Edit “Slow Query Analysis” Panel.</span>
<ul>
<li aria-level="1"><span>Now you should see the Query ID filter on the top.</span></li>
</ul>
</li>
<li aria-level="1"><span>Change the query to the following<br>
</span><br>
<pre class="urvanov-syntax-highlighter-plain-tag">SELECT
  period_start AS time,
  left(fingerprint, 80) AS query_text,
  sum(m_query_time_sum/m_query_time_cnt) AS query_time
FROM
  pmm.metrics
WHERE
  service_type = 'mysql'
  AND $__timeFilter(period_start)
  AND fingerprint IN (
    SELECT fingerprint
    FROM pmm.metrics
    WHERE service_type = 'mysql'
      AND $__timeFilter(period_start)
      AND ($queryid = '' OR queryid = $queryid)
    GROUP BY fingerprint
    ORDER BY sum(m_query_time_sum) DESC
    LIMIT 10
  )
GROUP BY
  time,
  fingerprint
ORDER BY
  time,
  query_time DESC</pre>
<ul>
<li aria-level="1"><span>Basically the query is fetching start time, query text and average query time for the selected period for the top 10 Queries in that time-frame.</span></li>
<li aria-level="1"><span>There is a filter for the “queryid” variable which you may use if you want to filter on a specific queryid.</span></li>
<li aria-level="1">Choose “Time Series” as “Query Type”<img loading="lazy" decoding="async" class="alignnone size-full wp-image-43352" src="https://www.percona.com/wp-content/uploads/2026/04/pmm-adding-query-1024x667-1.png" alt="" width="1024" height="667" srcset="https://www.percona.com/wp-content/uploads/2026/04/pmm-adding-query-1024x667-1.png 1024w, https://www.percona.com/wp-content/uploads/2026/04/pmm-adding-query-1024x667-1-300x195.png 300w, https://www.percona.com/wp-content/uploads/2026/04/pmm-adding-query-1024x667-1-768x500.png 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px"></li>
</ul>
</li>
<li aria-level="1"><span>Adjust Panel Options</span><span>11.1 Choose “Standard options” &gt; “Unit” as “Time / Seconds (s)” from drop down.</span><span>11.2 Choose “Standard options” &gt; “Display name” as “</span><span>${__field.labels.query_text}</span><span>”</span><span>11.3 Click on “Save Dashboard”</span></li>
<li><span> Your dashboard should be ready<img loading="lazy" decoding="async" class="alignnone size-full wp-image-43351" src="https://www.percona.com/wp-content/uploads/2026/04/pmm-sample-query-chart-1024x549-1.png" alt="" width="1024" height="549" srcset="https://www.percona.com/wp-content/uploads/2026/04/pmm-sample-query-chart-1024x549-1.png 1024w, https://www.percona.com/wp-content/uploads/2026/04/pmm-sample-query-chart-1024x549-1-300x161.png 300w, https://www.percona.com/wp-content/uploads/2026/04/pmm-sample-query-chart-1024x549-1-768x412.png 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px"></span></li>
</ol>
<p><span>Now, by default this dashboard is plotting top 10 queries. If you have a query fingerprint handy, you may be able to filter the search by that specific query.  That said, this is still plotting queries across all the monitored instances. Let’s move on to add the service_name filter.</span></p>
<p> </p>
<h3><b>Adding service_name filter</b></h3>
<ol>
<li aria-level="1"><span>Add Variable</span>
<ol>
<li aria-level="2"><span>Create new variable named “service_name”</span></li>
<li aria-level="2"><span>Use variable type “Query”</span></li>
<li aria-level="2"><span>Use Data Source as “ClickHouse”</span></li>
<li aria-level="2"><span>Query:<br>
</span><br>
<pre class="urvanov-syntax-highlighter-plain-tag">select distinct service_name from pmm.metrics where service_type = 'mysql';</pre>
</li>
<li><span>Unselect all checkboxes in “Selection options”</span></li>
<li><span>Save Dashboard</span></li>
</ol>
</li>
<li>Update Query</li>
</ol>
<p></p><pre class="urvanov-syntax-highlighter-plain-tag">SELECT
  period_start AS time,
  left(fingerprint, 80) AS query_text,
  sum(m_query_time_sum/m_query_time_cnt) AS query_time
FROM
  pmm.metrics
WHERE
  (service_name = '' OR service_name = '$service_name')
  AND service_type = 'mysql'
  AND $__timeFilter(period_start)
  AND fingerprint IN (
    SELECT fingerprint
    FROM pmm.metrics
    WHERE service_type = 'mysql'
      AND $__timeFilter(period_start)
      AND (service_name = '' OR service_name = '$service_name')
    GROUP BY fingerprint
    ORDER BY sum(m_query_time_sum) DESC
    LIMIT 10
  )
GROUP BY
  time,
  left(fingerprint, 80) 
ORDER BY
  time,
  query_time DESC</pre><p><span>I know many of you are naturally curious and enjoy experimenting with PMM and Grafana… So you’ve probably already started thinking about how far this can be taken. Feel free to share your ideas or custom dashboards in the comments.</span></p>
<p><span>Sample Dashboards:</span></p>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-43350" src="https://www.percona.com/wp-content/uploads/2026/04/pmm-dashboard-service-custom-1024x321-1.png" alt="" width="1024" height="321" srcset="https://www.percona.com/wp-content/uploads/2026/04/pmm-dashboard-service-custom-1024x321-1.png 1024w, https://www.percona.com/wp-content/uploads/2026/04/pmm-dashboard-service-custom-1024x321-1-300x94.png 300w, https://www.percona.com/wp-content/uploads/2026/04/pmm-dashboard-service-custom-1024x321-1-768x241.png 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px"> <img loading="lazy" decoding="async" class="alignnone size-full wp-image-43349" src="https://www.percona.com/wp-content/uploads/2026/04/pmm-sample-dashboard-1-1024x456-1.png" alt="" width="1024" height="456" srcset="https://www.percona.com/wp-content/uploads/2026/04/pmm-sample-dashboard-1-1024x456-1.png 1024w, https://www.percona.com/wp-content/uploads/2026/04/pmm-sample-dashboard-1-1024x456-1-300x134.png 300w, https://www.percona.com/wp-content/uploads/2026/04/pmm-sample-dashboard-1-1024x456-1-768x342.png 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px"></p>
<h1><span>The Query Analysis and Insights Dashboard</span></h1>
<p><span>Okay, for those who are looking to have quick results, I’ve prepared the complete Query Analysis and Insights Dashboard for you to import and use instantly.</span></p>
<p><span>By importing the JSON file, you’ll get the full working dashboard with all panels preconfigured, including:</span></p>
<ul>
<li><span>Slow Query Analysis</span></li>
<li><span>Latency Distribution Heatmap</span></li>
<li><span>Query Volatility (P99 vs Average)</span></li>
<li><span>Lock Wait Ratio Over Time (Top Contended Queries)</span></li>
<li><span>Temporary Table Usage (Disk &amp; Memory)</span></li>
<li><span>Query Efficiency (Rows Examined vs Rows Sent)</span></li>
<li><span>Error Rate vs Throughput</span></li>
<li><span>Workload Distribution by User</span></li>
<li><span>Query Volume by Client Host</span></li>
<li><span>Execution Time vs Lock Wait Time</span></li>
</ul>
<p><span>This allows you to instantly explore PMM Query Analytics data, adjust time ranges and filters, and correlate query performance, contention, and workload behavior without recreating the dashboard from scratch.</span></p>
<p><span>Dashboard JSON available here:</span></p>
<ul>
<li aria-level="1"><span>Grafana: https://grafana.com/grafana/dashboards/24896</span></li>
<li aria-level="1"><span>GitHub:  https://github.com/Percona-Lab/pmm-dashboards/query_analysis_insights.json</span></li>
</ul>
<p><span>Give it a go and let me know if you have suggestions or requests. Also consider sharing if you create something interesting.</span></p>
<p>Cheers.</p>
<p>The post <a href="https://www.percona.com/blog/building-query-analysis-and-insights-dashboard-in-pmm/">Building Query Analysis and Insights Dashboard in PMM</a> appeared first on <a href="https://www.percona.com/">Percona</a>.</p>]]></content:encoded>
    <pubDate>Mon, 04 May 2026 05:00:52 +0000</pubDate>
    <dc:creator>Kedar Vaijanapurkar</dc:creator>
    <category>Monitoring</category>
    <category>MySQL</category>
    <category>Percona Software</category>
  </item>

  <item>
    <title>Run an ALTER TABLE for a huge table in Aurora</title>
    <guid isPermaLink="false">https://www.percona.com/?p=43371</guid>
    <link>https://www.percona.com/blog/run-an-alter-table-for-a-huge-table-in-aurora/</link>
    <description>Recently, we received an alert for one of our Managed Services customers indicating that the auto_increment value for the table was 80% of its maximum capacity. The column was INT UNSIGNED, which has a limit of 4,294,967,295.
At 80%, we have enough time to change it to BIGINT.…. Right? Let’s see.
So we used pt-online-schema-change to perform the alter.
It started running at a good pace but slowed over time.
 
Why?
Well, let’s look at the definition of the table:mysql&amp;gt; show create table myschema.mytableG
*************************** 1. row ***************************
       Table: mytable
Create Table: CREATE TABLE `mytable` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `long_column` varchar(1000) NOT NULL,
  `state` tinyint unsigned NOT NULL,
  `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `short_column` varchar(30) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_long_column` (`long_column`,`state`),
  KEY `idx_short_column` (`short_column`,`state`),
  KEY `idx_short_col2` (`short_column`)
) ENGINE=InnoDB AUTO_INCREMENT=4009973818 DEFAULT CHARSET=utf8mb3NOTE1: The index on long_column is for a varchar column with a length of 1000; it may not be required, and an index prefix may be more helpful here.
NOTE2: The index idx_short_col2 is duplicated, as it is covered by the index idx_short_column.
Those changes require testing and are out of scope for this emergency, but they are worth mentioning.
 
Table size:
+---------------+------------+------------+---------+----------+---------+----------+--------+
| TABLE_SCHEMA  | TABLE_NAME | TABLE_ROWS | DATA_GB | INDEX_GB | FREE_GB | TOTAL_GB | ENGINE |
+---------------+------------+------------+---------+----------+---------+----------+--------+
| myschema      | mytable    | 3906921584 |    1118 |     1790 |       0 |     2907 | InnoDB |
+---------------+------------+------------+---------+----------+---------+----------+--------+Look at the indexes being way bigger than the data.mysql&amp;gt; SELECT database_name, table_name, index_name, ROUND(stat_value * @@innodb_page_size / 1024 / 1024, 2) AS size_in_mb FROM mysql.innodb_index_stats WHERE stat_name = 'size' AND index_name != 'PRIMARY' and database_name='myschema' and table_name='mytable' ORDER BY size_in_mb DESC;
+---------------+------------+-------------------+------------+
| database_name | table_name | index_name        | size_in_mb |
+---------------+------------+-------------------+------------+
| myschema      | mytable    | idx_long_column   | 1583538.95 |
| myschema      | mytable    | idx_short_column  |  126432.98 |
| myschema      | mytable    | idx_short_col2    |  122699.95 |
+---------------+------------+-------------------+------------+
3 rows in set (0.01 sec)While the pt-online-schema-change runs, it copies the data to a new table. As the data is being copied, the secondary indexes must be maintained.
NOTE the huge index for a varchar(1000) that is ~1.5T in size. Maintaining such an index becomes increasingly expensive as the data size increases.
The pt-online-schema-change had been running for ~8 days, and its latest estimate was 53 more days, which we can’t afford, since the maximum value would be exceeded in ~15 days. Copying `myschema`.`mytable`:  12% 53+16:48:01 remain
Copying `myschema`.`mytable`:  12% 53+16:48:30 remain
Copying `myschema`.`mytable`:  12% 53+16:48:59 remain
Copying `myschema`.`mytable`:  12% 53+16:49:26 remain
Copying `myschema`.`mytable`:  12% 53+16:49:53 remain
Copying `myschema`.`mytable`:  12% 53+16:50:19 remain
Copying `myschema`.`mytable`:  12% 53+16:50:49 remain
Copying `myschema`.`mytable`:  12% 53+16:51:17 remain
Copying `myschema`.`mytable`:  12% 53+16:51:45 remain 
So what do we do now?
We suggested canceling the pt-online-schema-change and creating an Aurora blue-green deployment.
Then perform the direct ALTER on the green cluster. And finally, when ready, do the failover.
 
Sounds good, doesn’t it?
 
First, we need to ensure that the new cluster (green) has the replica_type_conversions  parameter in its cluster parameter group to “ALL_NON_LOSSY, ALL_UNSIGNED” in order to be able to replicate from an int unsigned column to a bigint unsigned column.
So we tried that, it started too fast ~0.036% per minute, that’s 2 days. That’s great!
We left the process running over the weekend, but we noticed it started to slow down again… By Monday, it was advancing at ~0.01% every 5 mins, which gives an ETA of 34 days. 
Why? 
Again, using the direct ALTER MySQL copies the data to a temp table, and the bigger the data, the harder it is to maintain the indexes. 
Again, unacceptable.
Note that with the above 2 approaches, we lost ~12 days of precious time, and the deadline for auto_increment exhaustion was approaching.
Then we thought: What if we drop the secondary indexes, do the alter, and then add the indexes back?
In theory, it should be faster, as:

Dropping the indexes is a metadata-only operation with ONLINE DDL.
Altering the column datatype from INT to BIGINT is not an ONLINE operation, but the fact that it doesn’t have to update secondary indexes during row copying to a new temporary table prevents the slowdown.

Adding back the secondary indexes is an ONLINE DDL operation:

 
“Online DDL support for adding secondary indexes means that you can generally speed the overall process of creating and loading a table and associated indexes by creating the table without secondary indexes, then adding secondary indexes after the data is loaded.”
https://dev.mysql.com/doc/refman/8.4/en/innodb-online-ddl-operations.html
So let’s do this:
The deletion of the indexes was really quick, as expected (metadata-only operation):mysql&amp;gt; ALTER TABLE myschema.mytable DROP INDEX idx_long_column, DROP INDEX idx_short_column, DROP INDEX idx_short_col2;
Query OK, 0 rows affected (49.40 sec)
Records: 0  Duplicates: 0  Warnings: 0 
Then the change of the datatype:mysql&amp;gt; ALTER TABLE myschema.mytable CHANGE COLUMN id id bigint unsigned NOT NULL AUTO_INCREMENT;
Query OK, 4058047205 rows affected (13 hours 9 min 10.62 sec)
Records: 4058047205  Duplicates: 0  Warnings: 0 
Looks very promising!!!
 
The final step, add back the indexes:mysql&amp;gt; ALTER TABLE myschema.mytable ADD INDEX `idx_long_column` (`long_column`,`state`), ADD INDEX `idx_short_column` (`short_column`,`state`), ADD INDEX `short_col2` (`short_column`);
ERROR 1878 (HY000): Temporary file write failure. 
Why?
Well, the INPLACE operation uses the tmp dir to write sort files. In Aurora, there are certain limits for the temporary space based on the instance type. 
In a regular MySQL instance, we can modify the innodb_tmpdir to another location with enough disk space; however, in Aurora, the parameter is not modifiable, which could have made the whole process easier.
Even with a larger instance type, it’s hard to create the 1.5T index without breaking open the piggy bank.
 
Last resort, add the indexes back with the COPY algorithm:mysql&amp;gt; ALTER TABLE myschema.mytable ALGORITHM=COPY, ADD INDEX `idx_long_column` (`long_column`,`state`), ADD INDEX `idx_short_column` (`short_column`,`state`), ADD INDEX `idx_short_col2` (`short_column`);
Query OK, 4147498819 rows affected (6 days 1 hour 55 min 57.00 sec)
Records: 4147498819  Duplicates: 0  Warnings: 0 
Why does it work? Because ALTER TABLE using the COPY algorithm uses the datadir as the destination for the temporary table, the rows are copied there. It doesn’t have the limitation of the temporary directory mentioned above.
We were able to make it on time about 4 days before the auto_increment exhaustion, preventing downtime.
 
In retrospective we could have used the following approach to avoid the use of the blue/green deployment:

Perform a pt-online-schema-change on the main table, dropping the indexes, and changing the column type to bigint. ( with –no-swap-tables –no-drop-old-table –no-drop-new-table –no-drop-triggers).
Add the secondary indexes using the direct alter with the COPY algorithm in the _new table.
Once the alter finishes, swap the tables and drop the triggers.

 
Conclusion:
What initially looked like an easy task with pt-online-schema-change, ended up being more complex. 
You need to check the data definition, the index sizes, the Aurora limits, and how the different algorithms work to make a decision on the best way to proceed with those tasks, specially on situations like these where you have the pressure of the auto_increment being exhausted and there’s risk of downtime if it is not done on time.
And of course, monitor auto_increment exhaustion for your tables, and use a reasonable threshold that gives you enough time to plan and change the table definition. You can use Percona Monitoring and Management for this, specifically on the MySQL &amp;gt; MySQL Table Details dashboard.
The post Run an ALTER TABLE for a huge table in Aurora appeared first on Percona.</description>
    <content:encoded><![CDATA[<p><span>Recently, we received an alert for one of our </span><a href="https://www.percona.com/services/managed-services"><span>Managed Services</span></a><span> customers indicating that the auto_increment value for the table was 80% of its maximum capacity. The column was INT UNSIGNED, which has a limit of 4,294,967,295.</span></p>
<p><span>At 80%, we have enough time to change it to BIGINT.…. Right? Let’s see.</span></p>
<p><span>So we used </span><a href="https://docs.percona.com/percona-toolkit/pt-online-schema-change.html"><span>pt-online-schema-change</span></a><span> to perform the alter.</span></p>
<p><span>It started running at a good pace but slowed over time.</span></p>
<p> </p>
<p><b>Why?</b></p>
<p><span>Well, let’s look at the definition of the table:</span></p><pre class="urvanov-syntax-highlighter-plain-tag">mysql&gt; show create table myschema.mytableG
*************************** 1. row ***************************
       Table: mytable
Create Table: CREATE TABLE `mytable` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `long_column` varchar(1000) NOT NULL,
  `state` tinyint unsigned NOT NULL,
  `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `short_column` varchar(30) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_long_column` (`long_column`,`state`),
  KEY `idx_short_column` (`short_column`,`state`),
  KEY `idx_short_col2` (`short_column`)
) ENGINE=InnoDB AUTO_INCREMENT=4009973818 DEFAULT CHARSET=utf8mb3</pre><p><b>NOTE</b><b>1</b><b>: </b><span>The index on </span><i><span>long_column</span></i><span> is for a varchar column with a length of 1000; it may not be required, and an index prefix may be more helpful here.</span></p>
<p><b>NOTE</b><b>2</b><b>:</b><span> The index </span><i><span>idx_short_col2</span></i><span> is duplicated, as it is covered by the index </span><i><span>idx_short_column</span></i><span>.</span></p>
<p><span>Those changes require testing and are out of scope for this emergency, but they are worth mentioning.</span></p>
<p> </p>
<p><strong>Table size:</strong><span><br>
</span></p><pre class="urvanov-syntax-highlighter-plain-tag">+---------------+------------+------------+---------+----------+---------+----------+--------+
| TABLE_SCHEMA  | TABLE_NAME | TABLE_ROWS | DATA_GB | INDEX_GB | FREE_GB | TOTAL_GB | ENGINE |
+---------------+------------+------------+---------+----------+---------+----------+--------+
| myschema      | mytable    | 3906921584 |    1118 |     1790 |       0 |     2907 | InnoDB |
+---------------+------------+------------+---------+----------+---------+----------+--------+</pre><p><span>Look at the indexes being way bigger than the data.</span></p><pre class="urvanov-syntax-highlighter-plain-tag">mysql&gt; SELECT database_name, table_name, index_name, ROUND(stat_value * @@innodb_page_size / 1024 / 1024, 2) AS size_in_mb FROM mysql.innodb_index_stats WHERE stat_name = 'size' AND index_name != 'PRIMARY' and database_name='myschema' and table_name='mytable' ORDER BY size_in_mb DESC;
+---------------+------------+-------------------+------------+
| database_name | table_name | index_name        | size_in_mb |
+---------------+------------+-------------------+------------+
| myschema      | mytable    | idx_long_column   | 1583538.95 |
| myschema      | mytable    | idx_short_column  |  126432.98 |
| myschema      | mytable    | idx_short_col2    |  122699.95 |
+---------------+------------+-------------------+------------+
3 rows in set (0.01 sec)</pre><p><span>While the pt-online-schema-change runs, it copies the data to a new table. As the data is being copied, the secondary indexes must be maintained.</span></p>
<p><span>NOTE the huge index for a varchar(1000) that is ~1.5T in size. </span><span>Maintaining such an index becomes increasingly expensive as the data size increases.</span></p>
<p><span>The pt-online-schema-change had been running for ~8 days, and its latest estimate was 53 more days, which we can’t afford, since the maximum value would be exceeded in ~15 days. </span></p><pre class="urvanov-syntax-highlighter-plain-tag">Copying `myschema`.`mytable`:  12% 53+16:48:01 remain
Copying `myschema`.`mytable`:  12% 53+16:48:30 remain
Copying `myschema`.`mytable`:  12% 53+16:48:59 remain
Copying `myschema`.`mytable`:  12% 53+16:49:26 remain
Copying `myschema`.`mytable`:  12% 53+16:49:53 remain
Copying `myschema`.`mytable`:  12% 53+16:50:19 remain
Copying `myschema`.`mytable`:  12% 53+16:50:49 remain
Copying `myschema`.`mytable`:  12% 53+16:51:17 remain
Copying `myschema`.`mytable`:  12% 53+16:51:45 remain</pre><p> </p>
<p><span>So what do we do now?</span></p>
<p><span>We suggested canceling the pt-online-schema-change and creating an Aurora </span><a href="https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/blue-green-deployments-overview.html"><span>blue-green deployment</span></a><span>.</span></p>
<p><span>Then perform the direct ALTER on the green cluster. And finally, when ready, do the failover.</span></p>
<p> </p>
<p><span>Sounds good, doesn’t it?</span></p>
<p> </p>
<p><span>First, we need to ensure that the new cluster (green) has the </span><a href="https://dev.mysql.com/doc/refman/8.4/en/replication-options-replica.html#sysvar_replica_type_conversions"><b>replica_type_conversions</b></a><span>  parameter in its cluster parameter group to “</span><i><span>ALL_NON_LOSSY, ALL_UNSIGNED”</span></i><span> in order to be able to replicate from an int unsigned column to a bigint unsigned column.</span></p>
<p><span>So we tried that, it started too fast ~0.036% per minute, that’s 2 days. That’s great!</span></p>
<p><span>We left the process running over the weekend, but we noticed it started to slow down again… By Monday, it was advancing at ~0.01% every 5 mins, which gives an ETA of 34 days. </span></p>
<p><strong>Why? </strong></p>
<p><span>Again, using the direct ALTER MySQL copies the data to a temp table, and the bigger the data, the harder it is to maintain the indexes. </span></p>
<p><span>Again, unacceptable.</span></p>
<p><span>Note that with the above 2 approaches, we lost ~12 days of precious time, and the deadline for auto_increment exhaustion was approaching.</span></p>
<p><span>Then we thought: What if we drop the secondary indexes, do the alter, and then add the indexes back?</span></p>
<p><span>In theory, it should be faster, as:</span></p>
<ul>
<li aria-level="1"><span>Dropping the indexes is a metadata-only operation with </span><a href="https://dev.mysql.com/doc/refman/8.4/en/innodb-online-ddl-operations.html"><span>ONLINE DDL</span></a><span>.</span></li>
<li aria-level="1"><span>Altering the column datatype from INT to BIGINT is not an ONLINE operation, but the fact that it doesn’t have to update secondary indexes during row copying to a new temporary table prevents the slowdown.</span><span><br>
</span></li>
<li aria-level="1"><span>Adding back the secondary indexes is an ONLINE DDL operation:</span></li>
</ul>
<p> </p>
<p><span>“Online DDL support for adding secondary indexes means that you can generally speed the overall process of creating and loading a table and associated indexes by creating the table without secondary indexes, then adding secondary indexes after the data is loaded.”</span></p>
<p><a href="https://dev.mysql.com/doc/refman/8.4/en/innodb-online-ddl-operations.html"><span>https://dev.mysql.com/doc/refman/8.4/en/innodb-online-ddl-operations.html</span></a></p>
<p><span>So let’s do this:</span></p>
<p><span>The deletion of the indexes was really quick, as expected (metadata-only operation):</span></p><pre class="urvanov-syntax-highlighter-plain-tag">mysql&gt; ALTER TABLE myschema.mytable DROP INDEX idx_long_column, DROP INDEX idx_short_column, DROP INDEX idx_short_col2;
Query OK, 0 rows affected (49.40 sec)
Records: 0  Duplicates: 0  Warnings: 0</pre><p> </p>
<p><span>Then the change of the datatype:</span></p><pre class="urvanov-syntax-highlighter-plain-tag">mysql&gt; ALTER TABLE myschema.mytable CHANGE COLUMN id id bigint unsigned NOT NULL AUTO_INCREMENT;
Query OK, 4058047205 rows affected (13 hours 9 min 10.62 sec)
Records: 4058047205  Duplicates: 0  Warnings: 0</pre><p> </p>
<p><span>Looks very promising!!!</span></p>
<p> </p>
<p><span>The final step, add back the indexes:</span></p><pre class="urvanov-syntax-highlighter-plain-tag">mysql&gt; ALTER TABLE myschema.mytable ADD INDEX `idx_long_column` (`long_column`,`state`), ADD INDEX `idx_short_column` (`short_column`,`state`), ADD INDEX `short_col2` (`short_column`);
ERROR 1878 (HY000): Temporary file write failure.</pre><p> </p>
<p><b>Why?</b></p>
<p><span>Well, the INPLACE operation uses the tmp dir to write sort files. In Aurora, there are </span><a href="https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraMySQL.Managing.Performance.html#AuroraMySQL.Managing.TempStorage"><span>certain limits for the temporary space based on the instance type</span></a><span>. </span></p>
<p>In a regular MySQL instance, we can modify the <strong>innodb_tmpdir</strong> to another location with enough disk space; however, in Aurora, the parameter is not modifiable, which could have made the whole process easier.</p>
<p><span>Even with a larger instance type, it’s hard to create the 1.5T index without breaking open the piggy bank.</span></p>
<p> </p>
<p><b><i>Last resort</i></b><span>, add the indexes back with the COPY algorithm:</span></p><pre class="urvanov-syntax-highlighter-plain-tag">mysql&gt; ALTER TABLE myschema.mytable ALGORITHM=COPY, ADD INDEX `idx_long_column` (`long_column`,`state`), ADD INDEX `idx_short_column` (`short_column`,`state`), ADD INDEX `idx_short_col2` (`short_column`);
Query OK, 4147498819 rows affected (6 days 1 hour 55 min 57.00 sec)
<span>Records: 4147498819  Duplicates: 0  Warnings: 0</span></pre><p> </p>
<p><span>Why does it work? Because ALTER TABLE using the COPY algorithm uses the datadir as the destination for the temporary table, the rows are copied there. It doesn’t have the limitation of the temporary directory mentioned above.</span></p>
<p><span>We were able to make it on time about 4 days before the auto_increment exhaustion, preventing downtime.</span></p>
<p> </p>
<p><span>In retrospective we could have used the following approach to avoid the use of the blue/green deployment:</span></p>
<ol>
<li aria-level="1"><span>Perform a pt-online-schema-change on the main table, dropping the indexes, and changing the column type to bigint. ( with –no-swap-tables –no-drop-old-table –no-drop-new-table –no-drop-triggers).</span></li>
<li aria-level="1"><span>Add the secondary indexes using the direct alter with the COPY algorithm in the _new table.</span></li>
<li aria-level="1"><span>Once the alter finishes, swap the tables and drop the triggers.</span></li>
</ol>
<p> </p>
<h2><span>Conclusion:</span></h2>
<p><span>What initially looked like an easy task with </span><a href="https://docs.percona.com/percona-toolkit/pt-online-schema-change.html"><span>pt-online-schema-change</span></a><span>, ended up being more complex. </span></p>
<p><span>You need to check the data definition, the index sizes, the Aurora limits, and how the different algorithms work to make a decision on the best way to proceed with those tasks, specially on situations like these where you have the pressure of the auto_increment being exhausted and there’s risk of downtime if it is not done on time.</span></p>
<p><span>And of course, monitor auto_increment exhaustion for your tables, and use a reasonable threshold that gives you enough time to plan and change the table definition. You can use </span><a href="https://www.percona.com/software/database-tools/percona-monitoring-and-management"><span>Percona Monitoring and Management</span></a><span> for this, specifically on the MySQL &gt; MySQL Table Details dashboard.</span></p>
<p>The post <a href="https://www.percona.com/blog/run-an-alter-table-for-a-huge-table-in-aurora/">Run an ALTER TABLE for a huge table in Aurora</a> appeared first on <a href="https://www.percona.com/">Percona</a>.</p>]]></content:encoded>
    <pubDate>Fri, 01 May 2026 01:55:40 +0000</pubDate>
    <dc:creator>MySQL Performance Blog</dc:creator>
    <category>Cloud</category>
    <category>MySQL</category>
    <category>Percona Software</category>
  </item>

  <item>
    <title>MySQL Tuning on OCI HeatWave: What Still Matters, What OCI Manages, and What You Should Actually Tune</title>
    <guid isPermaLink="false">e2f499f811bbe02ae54aba0d200ae1bd</guid>
    <link>https://blogs.oracle.com/mysql/mysql-tuning-on-oci-heatwave-what-still-matters-what-oci-manages-and-what-you-should-actually-tune</link>
    <description>Once you move from self-managed MySQL to a MySQL DB System with HeatWave on OCI, the tuning story changes in an important way. On a self-managed server, you worry about two layers: MySQL and the operating system. On OCI MySQL DB Systems with HeatWave, Oracle runs your MySQL instance as a fully-managed service and explicitly […]</description>
    <pubDate>Thu, 30 Apr 2026 20:13:58 +0000</pubDate>
    <dc:creator>Oracle MySQL Group</dc:creator>
    <category>HeatWave AI</category>
    <category>MySQL</category>
    <category>MySQL HeatWave</category>
  </item>

  <item>
    <title>No More Silent Foreign Key Cascades: MySQL 9.7 Lets Child Triggers Speak Up</title>
    <guid isPermaLink="false">d07e9482743d52c4b09c79de4a813845</guid>
    <link>https://blogs.oracle.com/mysql/no-more-silent-foreign-key-cascades-mysql-9-7-lets-child-triggers-speak-up</link>
    <description>MySQL 9.7 introduces a long-requested improvement: Child table triggers are executed during SQL-layer foreign key cascades. Historically, cascades executed inside InnoDB did not invoke child table triggers, which created gaps in auditing, derived data maintenance, and observability. When a parent row change triggered cascading changes in child tables, those child table triggers were not executed. This […]</description>
    <pubDate>Thu, 30 Apr 2026 05:37:57 +0000</pubDate>
    <dc:creator>Oracle MySQL Group</dc:creator>
    <category>mysql</category>
    <category>mysqlcommunity</category>
  </item>

  <item>
    <title>Announcing Vitess 24</title>
    <guid isPermaLink="false">https://vitess.io/blog/2026-04-30-announcing-vitess-24/</guid>
    <link>https://vitess.io/blog/2026-04-30-announcing-vitess-24/</link>
    <description>Announcing Vitess 24 # The Vitess maintainers are happy to announce the release of version 24.0.0, along with version 2.17.0 of the Vitess Kubernetes Operator.
Version 24.0.0 expands query serving capabilities for sharded keyspaces, modernizes Vitess's observability stack, and introduces faster replica provisioning through native MySQL CLONE support. The companion v2.17.0 operator release brings significant improvements to scheduled backups, with new cluster- and keyspace-level schedules that make production backup management much easier to configure at scale.</description>
    <pubDate>Thu, 30 Apr 2026 00:00:00 +0000</pubDate>
    <dc:creator>Vitess</dc:creator>
    <category>release</category>
    <category>Vitess</category>
    <category>v24</category>
    <category>MySQL</category>
    <category>kubernetes</category>
    <category>operator</category>
    <category>vreplication</category>
    <category>tracing</category>
    <category>observability</category>
    <category>backup</category>
  </item>

  <item>
    <title>AI Is Raising the Bar for MySQL Database Security</title>
    <guid isPermaLink="false">73189ab761820afcaa529b3a1fe8b394</guid>
    <link>https://blogs.oracle.com/mysql/ai-is-raising-the-bar-for-mysql-database-security</link>
    <description>Best practices for MySQL customers and users in an AI-accelerated security landscape: A practical guide to hardening MySQL and the environment around it Oracle recently described how AI is transforming vulnerability detection and response. The latest generation of AI is increasing the speed and scale at which vulnerabilities can be identified and remediated. Oracle is […]</description>
    <pubDate>Wed, 29 Apr 2026 23:51:05 +0000</pubDate>
    <dc:creator>Oracle MySQL Group</dc:creator>
    <category>MySQL</category>
    <category>MySQL Community</category>
    <category>MySQL Enterprise</category>
    <category>AI security</category>
    <category>mysql</category>
    <category>mysqlcommunity</category>
    <category>Security</category>
  </item>

  <item>
    <title>XtraBackup incremental prepare phase is 2x-3x faster!</title>
    <guid isPermaLink="false">https://www.percona.com/?p=44623</guid>
    <link>https://www.percona.com/blog/xtrabackup-incremental-prepare-phase-is-2x-3x-faster/</link>
    <description>TL;DR
Percona XtraBackup is a 100% open-source backup solution for Percona Server for MySQL and MySQL®. It is designed for high-availability environments, performing online, non-blocking, and highly secure backups of transactional systems without interrupting your production traffic.
While full backups work for small databases, large-scale systems rely on incremental backups to save space and time. However, the “prepare” stage, required to make the incremental backups consistent, was slow because XtraBackup processed the .delta files serially. The .delta files are generated per table and store only the modifications since the last backup.
Great news! In XtraBackup versions 8.0.35-33 and 8.4.0-3 and later, we’ve added support for the --parallel option during the prepare stage. This option lets XtraBackup process multiple .delta files simultaneously, significantly reducing the preparation time, especially when you have a large number of IBD files.
Please add --parallel=X, with the number of threads to use, to the xtrabackup --prepare --apply-log-only command to speed up the incremental prepare operation.
The Incremental Backup Workflow
Before we dive into the performance gains, it’s important to understand how Incremental backups work.
1. Creating the Backups
The process starts with a full backup followed by a backup that captures the changes since the last backup. This smaller backup is called an incremental backup. XtraBackup creates .delta files during incremental backups. Let’s review an example.

Take Full Backup: Your starting point is Point A. This backup is an entire copy of your data.
Take Inc1 Backup: XtraBackup identifies the changes between Point A and Point B. It creates a .delta file for every table that has been changed. Delta files contain only the pages that changed between the backups.
Take Inc2 Backup: XtraBackup identifies the changes between Point B and Point C. It creates a new set of .delta files for this specific period.

For more detailed steps/commands, please check the documentation here: https://docs.percona.com/percona-xtrabackup/8.0/create-incremental-backup.html
2. Preparing the Backups
To restore the data to the latest point, you must merge these changes back into the full backup. The “prepare” phase works differently here:

Prepare Inc1: You merge the Inc1 changes into the full backup using the --apply-log-only option. In this step, XtraBackup applies the .delta files and the redo logs, but does not apply the Undo logs
Prepare Inc2: You merge the Inc2 changes into the updated base using the --apply-log-only option. XtraBackup applies the .delta files and the Redo logs but skips the Undo logs.
Final Prepare: After all the incremental backups are merged, you run a final prepare command on the full backup. This final step applies the Undo logs to make the entire dataset consistent. If you apply the Undo logs during the intermediate steps, you cannot merge any further backups.

More detailed steps to prepare an incremental backup are described here: https://docs.percona.com/percona-xtrabackup/8.0/prepare-incremental-backup.html
The Improvement: Parallel Incremental Delta Apply
We have improved the Incremental Delta Apply phase. These are “Prepare inc1” and “Prepare inc2” phases as described above. --parallel option should be used along with the --apply-log-only to apply the .delta files in parallel.
We completed this essential improvement as part of [PXB-3427].
In previous versions, XtraBackup applied the .delta files as soon as a file was discovered in the incremental backup directory. Starting with versions 8.0.35-33 and 8.4.0-3, to apply the .delta files, XtraBackup scans the backup directory and builds a queue of delta files. Multiple threads (defined by --parallel ) consume this queue simultaneously. Each thread reads a .delta file and writes its pages to the corresponding InnoDB Data File (.ibd file).
Benchmarks
This benchmark is created using the scripts, and the instructions are in JIRA: PXB-3427

When your backup contains a large number of small .delta files, increasing the --parallel value can drastically reduce the time taken to prepare the incremental backup by distributing the high per-file overhead across more threads. However, for other categories with fewer or larger files, performance typically plateaus after 16 threads, and pushing higher can even lead to slight regressions due to thread management overhead. While there is no single “golden value” to recommend for every scenario, we recommend starting with a value of 8 to find the optimal balance for your specific environment.
Disk Utilization with XtraBackup prepare using --parallel=1 vs --parallel=64
The PMM graphs below show the Disk IOPs used by the XtraBackup prepare command. The graph is generated when XtraBackup applies the incremental backup to a full backup directory. Incremental backup directory that has 20,608 .delta files, each of which is 2.5 MB.
With --parallel=1

With --parallel=1, max Disk IOPs utilized is 18.2 K, and the XtraBackup prepare operation finished in 3.76 minutes.
With --parallel=64


 
With --parallel=64, the max Disk Write IOPs utilized is 85K, and the XtraBackup prepare operation finished in around a minute. XtraBackup utilized 4.67x more disk IOPS and finished 3.49x faster.
Results from the bug reporter
We saw some amazing results shared by the reporter on PXB-3427.  The time required for XtraBackup prepare command (--prepare --apply-log-only)  to complete, reduced from 237 minutes to just 6 minutes. That’s an incredible 40X speed-up!
Here are the details from their setup:

Full backup: 235,188 *.ibd files
Incremental backup: 236,214 *.ibd.delta files
Average .delta size: 53,041 bytes (~53KB)
Threads used: 48 (–parallel=48)
Disk specs: 25K IOPS performance and an average of 500 to 600 MB/s of throughput

We hear you! This specific feature came to us from a post on the community forum. We reached out, asked them to create a JIRA ticket, and then implemented the improvement. We wanted to share this story as a demonstration of our commitment to listening to and acting on community feedback!
The post XtraBackup incremental prepare phase is 2x-3x faster! appeared first on Percona.</description>
    <content:encoded><![CDATA[<h2><b>TL;DR</b></h2>
<p><b>Percona XtraBackup</b> is a 100% open-source backup solution for Percona Server for MySQL and MySQL®. It is designed for high-availability environments, performing online, non-blocking, and highly secure backups of transactional systems without interrupting your production traffic.</p>
<p>While <a href="https://docs.percona.com/percona-xtrabackup/8.0/create-full-backup.html">full backups</a> work for small databases, large-scale systems rely on <a href="https://docs.percona.com/percona-xtrabackup/8.0/create-incremental-backup.html"><b>incremental backups</b></a> to save space and time. However, the “prepare” stage, required to make the incremental backups consistent, was slow because XtraBackup processed the .delta files serially. The .delta files are generated per table and store only the modifications since the last backup.</p>
<p>Great news! In XtraBackup versions <span><b>8.0.35-33</b></span> and <span><b>8.4.0-3</b></span> and later, we’ve added support for the <code><a href="https://docs.percona.com/percona-xtrabackup/8.0/xtrabackup-option-reference.html#parallel">--parallel</a></code> option during the prepare stage. This option lets XtraBackup process multiple .delta files simultaneously, <i>significantly</i> reducing the preparation time, especially when you have a large number of IBD files.</p>
<p>Please add <code><i><strong>--parallel=X</strong></i></code>, with the number of threads to use, to the <code><i><strong>xtrabackup --prepare --apply-log-only</strong></i></code> command to speed up the<a href="https://docs.percona.com/percona-xtrabackup/8.0/prepare-incremental-backup.html#faster-prepare-step-with-parallel"> incremental prepare</a> operation.</p>
<h2><b>The Incremental Backup Workflow</b></h2>
<p>Before we dive into the performance gains, it’s important to understand how Incremental backups work.</p>
<h3><b>1. Creating the Backups</b></h3>
<p>The process starts with a full backup followed by a backup that captures the changes since the last backup. This smaller backup is called an incremental backup. XtraBackup creates .delta files during incremental backups. Let’s review an example.</p>
<ul>
<li aria-level="1"><b>Take Full Backup:</b> Your starting point is Point A. This backup is an entire copy of your data.</li>
<li aria-level="1"><b>Take Inc1 Backup:</b> XtraBackup identifies the changes between Point A and Point B. It creates a .delta file for every table that has been changed. Delta files contain only the pages that changed between the backups.</li>
<li aria-level="1"><b>Take Inc2 Backup:</b> XtraBackup identifies the changes between Point B and Point C. It creates a new set of .delta files for this specific period.</li>
</ul>
<p>For more detailed steps/commands, please check the documentation here: <a href="https://docs.percona.com/percona-xtrabackup/8.0/create-incremental-backup.html">https://docs.percona.com/percona-xtrabackup/8.0/create-incremental-backup.html</a></p>
<h3><b>2. Preparing the Backups</b></h3>
<p>To restore the data to the latest point, you must merge these changes back into the full backup. The “prepare” phase works differently here:</p>
<ul>
<li aria-level="1"><b>Prepare Inc1:</b> You merge the Inc1 changes into the full backup using the <code><i>--apply-log-only</i></code> option. In this step, XtraBackup applies the .delta files and the redo logs, but does <b>not</b> apply the Undo logs</li>
<li aria-level="1"><b>Prepare Inc2:</b> You merge the Inc2 changes into the updated base using the <code><i>--apply-log-only</i></code> option. XtraBackup applies the .delta files and the Redo logs but skips the Undo logs.</li>
<li aria-level="1"><b>Final Prepare:</b> After all the incremental backups are merged, you run a final prepare command on the full backup. This final step applies the <b>Undo logs</b> to make the entire dataset consistent. If you apply the Undo logs during the intermediate steps, you cannot merge any further backups.</li>
</ul>
<p>More detailed steps to prepare an incremental backup are described here: <a href="https://docs.percona.com/percona-xtrabackup/8.0/prepare-incremental-backup.html">https://docs.percona.com/percona-xtrabackup/8.0/prepare-incremental-backup.html</a></p>
<h2><b>The Improvement: Parallel Incremental Delta Apply</b></h2>
<p>We have improved the <b>Incremental Delta Apply</b> phase. These are “<b>Prepare inc1”</b> and “<b>Prepare inc2</b>” phases as described above. <code><a href="https://docs.percona.com/percona-xtrabackup/8.0/xtrabackup-option-reference.html#parallel">--parallel</a></code> option should be used along with the <code>--apply-log-only</code> to apply the .delta files in parallel.</p>
<p>We completed this essential improvement as part of <b>[</b><a href="https://perconadev.atlassian.net/browse/PXB-3427"><b>PXB-3427</b></a><b>]</b>.</p>
<p>In previous versions, XtraBackup applied the .delta files as soon as a file was discovered in the incremental backup directory. Starting with versions <b>8.0.35-33</b> and <b>8.4.0-3</b>, to apply the .delta files, XtraBackup scans the backup directory and builds a queue of delta files. Multiple threads (defined by <code><a href="https://docs.percona.com/percona-xtrabackup/8.0/xtrabackup-option-reference.html#parallel">--parallel</a></code> ) consume this queue simultaneously. Each thread reads a .delta file and writes its pages to the corresponding InnoDB Data File (.ibd file).</p>
<h2><b>Benchmarks</b></h2>
<p>This benchmark is created using the scripts, and the instructions are in JIRA: <a href="https://perconadev.atlassian.net/browse/PXB-3427?focusedCommentId=454634">PXB-3427</a></p>
<p><img loading="lazy" decoding="async" class="alignnone size-large wp-image-44624" src="https://www.percona.com/wp-content/uploads/2026/04/prepare_performance_plot-1024x640.png" alt="xtrabackup prepare performance" width="1024" height="640" srcset="https://www.percona.com/wp-content/uploads/2026/04/prepare_performance_plot-1024x640.png 1024w, https://www.percona.com/wp-content/uploads/2026/04/prepare_performance_plot-300x188.png 300w, https://www.percona.com/wp-content/uploads/2026/04/prepare_performance_plot-768x480.png 768w, https://www.percona.com/wp-content/uploads/2026/04/prepare_performance_plot-1536x960.png 1536w, https://www.percona.com/wp-content/uploads/2026/04/prepare_performance_plot-2048x1280.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px"></p>
<p>When your backup contains a large number of small .delta files, increasing the <code><a href="https://docs.percona.com/percona-xtrabackup/8.0/xtrabackup-option-reference.html#parallel">--parallel</a></code> value can drastically reduce the time taken to prepare the incremental backup by distributing the high per-file overhead across more threads. However, for other categories with fewer or larger files, performance typically plateaus after <b>16 threads</b>, and pushing higher can even lead to slight regressions due to thread management overhead. While there is no single “golden value” to recommend for every scenario, we recommend starting with a value of <b>8</b> to find the optimal balance for your specific environment.</p>
<h2><b>Disk Utilization with XtraBackup prepare using <code>--parallel=1</code> vs <code>--parallel=64</code></b></h2>
<p>The <a href="https://www.percona.com/monitoring/">PMM</a> graphs below show the Disk IOPs used by the XtraBackup prepare command. The graph is generated when XtraBackup applies the incremental backup to a full backup directory. Incremental backup directory that has 20,608 .delta files, each of which is 2.5 MB.</p>
<h3><b>With <code>--parallel=1</code></b></h3>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-44625" src="https://www.percona.com/wp-content/uploads/2026/04/parallel_00.png" alt="xtrabackup incremental disk IOPs with --parllel=1" width="713" height="392" srcset="https://www.percona.com/wp-content/uploads/2026/04/parallel_00.png 713w, https://www.percona.com/wp-content/uploads/2026/04/parallel_00-300x165.png 300w" sizes="auto, (max-width: 713px) 100vw, 713px"></p>
<p>With <code>--parallel=1</code>, max Disk IOPs utilized is 18.2 K, and the XtraBackup prepare operation finished in 3.76 minutes.</p>
<h3><b>With <code>--parallel=64</code></b><b><br>
</b></h3>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-44626" src="https://www.percona.com/wp-content/uploads/2026/04/parallel_64_11.png" alt="xtrabackup incremental delta prepare performance with parallel 64" width="719" height="404" srcset="https://www.percona.com/wp-content/uploads/2026/04/parallel_64_11.png 719w, https://www.percona.com/wp-content/uploads/2026/04/parallel_64_11-300x169.png 300w" sizes="auto, (max-width: 719px) 100vw, 719px"></p>
<p> </p>
<p>With <code><strong>--parallel=64</strong></code>, the max Disk Write IOPs utilized is 85K, and the XtraBackup prepare operation finished in around a minute. XtraBackup utilized<b> 4.67x</b> more disk IOPS and finished <b>3.49x</b> faster.</p>
<h2><b>Results from the bug reporter</b></h2>
<p>We saw some amazing results shared by the reporter on <a href="https://perconadev.atlassian.net/browse/PXB-3427">PXB-3427</a>.  The time required for XtraBackup prepare command (<code>--prepare --apply-log-only</code>)  to complete, reduced from <b>237 minutes to just 6 minutes</b>. That’s an incredible <b>40X speed-up</b>!</p>
<p>Here are the details from their setup:</p>
<ul>
<li aria-level="1"><b>Full backup:</b> 235,188 *.ibd files</li>
<li aria-level="1"><b>Incremental backup:</b> 236,214 *.ibd.delta files</li>
<li aria-level="1"><b>Average </b><b>.delta</b><b> size:</b> 53,041 bytes (~53KB)</li>
<li aria-level="1"><b>Threads used:</b> 48 (–parallel=48)</li>
<li aria-level="1"><b>Disk specs:</b> 25K IOPS performance and an average of 500 to 600 MB/s of throughput</li>
</ul>
<p><b>We hear you!</b> This specific feature came to us from a post on the community <a href="https://forums.percona.com/t/mysql-8-4-disabling-innodb-redo-log-during-restore-safe-practice/35675">forum</a>. We reached out, asked them to create a JIRA ticket, and then implemented the improvement. We wanted to share this story as a demonstration of our commitment to listening to and acting on community feedback!</p>
<p>The post <a href="https://www.percona.com/blog/xtrabackup-incremental-prepare-phase-is-2x-3x-faster/">XtraBackup incremental prepare phase is 2x-3x faster!</a> appeared first on <a href="https://www.percona.com/">Percona</a>.</p>]]></content:encoded>
    <pubDate>Wed, 29 Apr 2026 18:52:44 +0000</pubDate>
    <dc:creator>MySQL Performance Blog</dc:creator>
    <category>MySQL</category>
    <category>Open Source</category>
    <category>Xtrabackup</category>
    <category>.delta file</category>
    <category>apply-log-only</category>
    <category>incremental</category>
    <category>incremental backup</category>
    <category>MySQL Backup</category>
    <category>MySQL Backup tools</category>
    <category>Percona XtraBackup</category>
    <category>prepare</category>
    <category>xtrabackup</category>
  </item>

  <item>
    <title>Orchestrator’s Next Chapter: What It Means for Percona Customers</title>
    <guid isPermaLink="false">https://www.percona.com/?p=45274</guid>
    <link>https://www.percona.com/blog/orchestrators-next-chapter-what-it-means-for-percona-customers/</link>
    <description>Last week, ProxySQL announced that they are taking over the maintenance and development of Orchestrator, the MySQL high-availability and topology management tool originally authored by Shlomi Noach. You can read their announcement here: Announcing the future of Orchestrator.
We want to briefly share Percona’s position on the news.
We welcome this
Orchestrator became the de facto standard for MySQL topology management and automated failover, and it has been a foundational tool in the ecosystem for over a decade. When the upstream project was archived, many operators were left running internal forks. A revived project under active development, with a stated roadmap and continued Apache 2.0 licensing, is good news for the MySQL community, and we’re glad to see ProxySQL step up to take it on. Thanks are due to Shlomi Noach for creating Orchestrator in the first place, and to everyone who contributed to it over the years.
A small clarification on Percona’s role
The ProxySQL announcement kindly credited Percona alongside GitHub for “stewardship over the years.” To be accurate: Percona has never been a maintainer of the upstream Orchestrator project. What we have done, and will continue to do, is support our customers who rely on it. That includes operational guidance, troubleshooting, and carrying internal patches where a customer situation requires it. The upstream project itself has always lived with Shlomi and later with the team at GitHub.
Nothing changes for Percona customers
If you are a Percona customer running Orchestrator today, your support experience is unchanged. We will continue helping you operate it in production, diagnose issues, and plan around its role in your high-availability stack. That commitment is steady regardless of where the upstream project lives.
Orchestrator’s maintenance also matters to us beyond support engagements. Percona Operator for MySQL uses Orchestrator to manage asynchronous topologies, so our own product depends on the project staying healthy. That’s part of why we plan to coordinate closely with the ProxySQL team as the next chapter unfolds.
Coordinating with the ProxySQL team
We plan to open coordination conversations with the ProxySQL team to make sure that operators running Orchestrator today, including our customers, have a smooth path as the project evolves. We wish the ProxySQL team well in this next chapter and look forward to supporting the community alongside them.
If you’re a Percona customer, reach out to your account team with any questions about your Orchestrator deployment. If you’re running Orchestrator outside of a Percona engagement and want to talk through support options, get in touch with our MySQL team.
 

The post Orchestrator’s Next Chapter: What It Means for Percona Customers appeared first on Percona.</description>
    <content:encoded><![CDATA[<p>Last week, ProxySQL announced that they are taking over the maintenance and development of Orchestrator, the MySQL high-availability and topology management tool originally authored by Shlomi Noach. You can read their announcement here: <a href="https://proxysql.com/blog/announcing-proxysql-takes-over-orchestrator/" target="_blank" rel="noopener">Announcing the future of Orchestrator</a>.</p>
<p>We want to briefly share Percona’s position on the news.</p>
<h4>We welcome this</h4>
<p>Orchestrator became the de facto standard for MySQL topology management and automated failover, and it has been a foundational tool in the ecosystem for over a decade. When the upstream project was archived, many operators were left running internal forks. A revived project under active development, with a stated roadmap and continued Apache 2.0 licensing, is good news for the MySQL community, and we’re glad to see ProxySQL step up to take it on. Thanks are due to Shlomi Noach for creating Orchestrator in the first place, and to everyone who contributed to it over the years.</p>
<h4>A small clarification on Percona’s role</h4>
<p>The ProxySQL announcement kindly credited Percona alongside GitHub for “stewardship over the years.” To be accurate: Percona has never been a maintainer of the upstream Orchestrator project. What we have done, and will continue to do, is support our customers who rely on it. That includes operational guidance, troubleshooting, and carrying internal patches where a customer situation requires it. The upstream project itself has always lived with Shlomi and later with the team at GitHub.</p>
<h4>Nothing changes for Percona customers</h4>
<p>If you are a Percona customer running Orchestrator today, your support experience is unchanged. We will continue helping you operate it in production, diagnose issues, and plan around its role in your high-availability stack. That commitment is steady regardless of where the upstream project lives.</p>
<p>Orchestrator’s maintenance also matters to us beyond support engagements. Percona Operator for MySQL uses Orchestrator to manage asynchronous topologies, so our own product depends on the project staying healthy. That’s part of why we plan to coordinate closely with the ProxySQL team as the next chapter unfolds.</p>
<h4>Coordinating with the ProxySQL team</h4>
<p>We plan to open coordination conversations with the ProxySQL team to make sure that operators running Orchestrator today, including our customers, have a smooth path as the project evolves. We wish the ProxySQL team well in this next chapter and look forward to supporting the community alongside them.</p>
<p>If you’re a Percona customer, reach out to your account team with any questions about your Orchestrator deployment. If you’re running Orchestrator outside of a Percona engagement and want to talk through support options, <a href="https://www.percona.com/mysql/support/">get in touch with our MySQL team</a>.</p>
<p> </p>
<p><!-- notionvc: 1a4652ac-6c9a-433e-8656-d58627a32d40 --></p>
<p>The post <a href="https://www.percona.com/blog/orchestrators-next-chapter-what-it-means-for-percona-customers/">Orchestrator’s Next Chapter: What It Means for Percona Customers</a> appeared first on <a href="https://www.percona.com/">Percona</a>.</p>]]></content:encoded>
    <pubDate>Wed, 29 Apr 2026 17:55:10 +0000</pubDate>
    <dc:creator>MySQL Performance Blog</dc:creator>
    <category>Cloud</category>
    <category>Kubernetes</category>
    <category>MySQL</category>
    <category>Operator</category>
    <category>ProxySQL</category>
  </item>

  <item>
    <title>Introducing the Change Stream Applier (CSA): A New MySQL Replication Applier in Labs</title>
    <guid isPermaLink="false">d58830a866aaa70e1e7b98f4dcb178ed</guid>
    <link>https://blogs.oracle.com/mysql/introducing-the-change-stream-applier-csa-a-new-mysql-replication-applier-in-labs</link>
    <description>Introduction Replication performance depends on every stage in the pipeline, from the source database to transport and ultimately to commit on the replica. On the replica side, much of that performance comes down to how efficiently changes are read, scheduled, and applied under real operational pressure. In practice, that directly affects steady-state lag, backlog recovery […]</description>
    <pubDate>Wed, 29 Apr 2026 13:39:58 +0000</pubDate>
    <dc:creator>Oracle MySQL Group</dc:creator>
    <category>MySQL</category>
    <category>MySQL Community</category>
    <category>Database</category>
    <category>mysql</category>
    <category>mysqlcommunity</category>
    <category>OpenSource</category>
    <category>Performance</category>
    <category>Replication</category>
  </item>

  <item>
    <title>The hypergraph optimizer is now available in MySQL 9.7 Community Edition</title>
    <guid isPermaLink="false">tag:blogger.com,1999:blog-1508669603650457962.post-3998264298444207249</guid>
    <link>https://oysteing.blogspot.com/2026/04/the-hypergraph-optimizer-is-now.html</link>
    <description>I have written a new post on the MySQL blog about the hypergraph optimizer, which is now available in MySQL 9.7 Community Edition.

The post gives a high-level technical overview of what is different from the classic join optimizer, why it can produce better plans for some multi-table queries, and where it is most useful to try. It also includes early benchmark results and some caveats, since the feature is still evolving and remains off by default.</description>
    <content:encoded><![CDATA[I have written a <a href="https://blogs.oracle.com/mysql/the-hypergraph-optimizer-is-now-available-in-mysql-9-7-community-edition">new post on the MySQL blog</a> about the hypergraph optimizer, which is now available in MySQL 9.7 Community Edition.

The post gives a high-level technical overview of what is different from the classic join optimizer, why it can produce better plans for some multi-table queries, and where it is most useful to try. It also includes early benchmark results and some caveats, since the feature is still evolving and remains off by default.]]></content:encoded>
    <pubDate>Tue, 28 Apr 2026 14:15:00 +0000</pubDate>
    <dc:creator>Øystein Grøvlen</dc:creator>
  </item>

  <item>
    <title>Strengthening the MySQL Community: Highlights from Our Third Public Discussion</title>
    <guid isPermaLink="false">3b7c05af1f41f2653323d715e84efc28</guid>
    <link>https://blogs.oracle.com/mysql/strengthening-the-mysql-community-highlights-from-our-third-public-discussion</link>
    <description>On April 21, 2026, our third public discussion continued the conversation around transparency, participation, and the future of MySQL. Building on the momentum from earlier sessions, the discussion focused on progress and improvements to increase community transparency and practical ways for community members to get involved. At the center of the discussion was the MySQL […]</description>
    <pubDate>Mon, 27 Apr 2026 23:56:35 +0000</pubDate>
    <dc:creator>Oracle MySQL Group</dc:creator>
    <category>MySQL</category>
    <category>MySQL Community</category>
    <category>mysql</category>
    <category>mysqlcommunity</category>
  </item>

  <item>
    <title>The hypergraph optimizer is now available in MySQL 9.7 Community Edition</title>
    <guid isPermaLink="false">e0c08cd68eec3f87536af225eab041bc</guid>
    <link>https://blogs.oracle.com/mysql/the-hypergraph-optimizer-is-now-available-in-mysql-9-7-community-edition</link>
    <description>MySQL 9.7 Community Edition now includes the hypergraph optimizer as an alternative to the classic join optimizer, making this capability available across all MySQL editions. This is not a cosmetic change. The hypergraph optimizer uses a new join-planning framework aimed at queries where plan shape can make a real difference, particularly for multi-table joins, workloads […]</description>
    <pubDate>Mon, 27 Apr 2026 17:19:22 +0000</pubDate>
    <dc:creator>Oracle MySQL Group</dc:creator>
    <category>MySQL</category>
    <category>MySQL Community</category>
    <category>hypergraph optimizer</category>
    <category>mysql</category>
    <category>query optimization</category>
  </item>

  <item>
    <title>MySQL Tuning: Is It Mostly MySQL, or Does the Operating System Matter Also?</title>
    <guid isPermaLink="false">66ffd5ed8053a65e4261b1aa9c011730</guid>
    <link>https://blogs.oracle.com/mysql/mysql-tuning-is-it-mostly-mysql-or-does-the-operating-system-matter-also</link>
    <description>When people ask me how to tune MySQL, they usually mean, “Which variables should I change in my.cnf?” (the MySQL configuration file) That certainly is a reasonable place to start, because most day-to-day performance tuning really is driven by MySQL itself: memory allocation, redo flushing, connection handling, temporary tables, and InnoDB I/O behavior. But the […]</description>
    <pubDate>Fri, 24 Apr 2026 20:15:25 +0000</pubDate>
    <dc:creator>Oracle MySQL Group</dc:creator>
    <category>MySQL</category>
    <category>MySQL Community</category>
    <category>MySQL Enterprise</category>
    <category>mysql</category>
    <category>mysqlcommunity</category>
  </item>

  <item>
    <title>Upcoming MySQL Events and Webinars (Updated list for April–May 2026)  </title>
    <guid isPermaLink="false">bb06594bf2349302f1cef9104db088e9</guid>
    <link>https://blogs.oracle.com/mysql/upcoming-mysql-events-and-webinars-updated-list-for-april-may-2026</link>
    <description>As an update to our recent blog post, “Where can you find MySQL next? (Updated events list for March–May 2026)” we’d like to share the latest confirmed MySQL events and webinars, including newly added ones plus refreshed details for sessions we already announced. Since plans and agendas evolve quickly, this post is intended to provide […]</description>
    <pubDate>Thu, 23 Apr 2026 18:26:29 +0000</pubDate>
    <dc:creator>Oracle MySQL Group</dc:creator>
    <category>MySQL</category>
    <category>MySQL Community</category>
  </item>

  <item>
    <title>MySQL Community Roadmap Update and Invitation: MySQL Contributor Summit</title>
    <guid isPermaLink="false">52b01fcf2fca40e7fa784f5aa2376a73</guid>
    <link>https://blogs.oracle.com/mysql/mysql-community-roadmap-update-and-invitation-mysql-contributor-summit</link>
    <description>As part of our MySQL community engagement plan, which includes delivering new features into MySQL Community Edition, increasing collaboration and transparency, and expanding and growing the MySQL Ecosystem, we have created a new rhythm of public MySQL Community Discussions—starting with our first session on February 25 and continuing with our second session on March 23, […]</description>
    <pubDate>Thu, 23 Apr 2026 07:36:30 +0000</pubDate>
    <dc:creator>Oracle MySQL Group</dc:creator>
    <category>MySQL</category>
    <category>MySQL Community</category>
  </item>

  <item>
    <title>Introducing Dynamic Data Masking in MySQL: Protect Sensitive Data Without App Changes</title>
    <guid isPermaLink="false">4fc34cd4cea3926189df67128c4752fb</guid>
    <link>https://blogs.oracle.com/mysql/introducing-dynamic-data-masking-in-mysql-protect-sensitive-data-without-app-changes</link>
    <description>Production data is invaluable for day-to-day operations—support, troubleshooting, analytics, and development. But when that data contains sensitive fields such as SSNs, emails, phone numbers, or other identifiers, broad read access can quickly become unnecessary exposure.  Just as importantly, many organizations operate under regulatory and contractual requirements that expect strong controls around access to sensitive data—often including data masking as […]</description>
    <pubDate>Wed, 22 Apr 2026 21:56:42 +0000</pubDate>
    <dc:creator>Oracle MySQL Group</dc:creator>
    <category>MySQL</category>
    <category>MySQL Enterprise</category>
  </item>

  <item>
    <title>Upgrade to OpenSSL 3.5</title>
    <guid isPermaLink="false">4d0b2c6ff1d4dcd9daea05042f829b71</guid>
    <link>https://blogs.oracle.com/mysql/upgrade-to-openssl-3-5</link>
    <description>Overview Some MySQL distribution packages, such as the generic Linux build, bundle an OpenSSL dependency within the same .tar.gz archive. With the new MySQL 8.0.46, 8.4.9 and 9.7.0 releases, we are upgrading those bundled packages from using OpenSSL 3.0 to the new OpenSSL 3.5 LTS branch. Native OS packages, such as .rpm and .deb, continue […]</description>
    <pubDate>Wed, 22 Apr 2026 05:28:53 +0000</pubDate>
    <dc:creator>Oracle MySQL Group</dc:creator>
    <category>MySQL Community</category>
    <category>mysql</category>
    <category>mysqlcommunity</category>
    <category>openssl</category>
    <category>Performance</category>
    <category>Security</category>
    <category>upgrades</category>
  </item>

  <item>
    <title>MySQL Performance : OpenSSL-3.5.5 Evaluation</title>
    <guid isPermaLink="false">http://dimitrik.free.fr/blog/posts/mysql-perf-openssl355-evaluation.html</guid>
    <link>http://dimitrik.free.fr/blog/posts/mysql-perf-openssl355-evaluation.html</link>
    <description>The following report is covering performance evaluation of the currently available OpenSSL releases when they are used by MySQL in CPU-intensive OLTP workloads. However, the main focus is on OpenSSL-3.5.5, which will be used by default in the next MySQL releases.
Read more... (19 min remaining to read)</description>
    <content:encoded><![CDATA[<div><p>The following report is covering performance evaluation of the currently available OpenSSL releases when they are used by MySQL in CPU-intensive OLTP workloads. However, the main focus is on OpenSSL-3.5.5, which will be used by default in the next MySQL releases.</p>
<p><a href="http://dimitrik.free.fr/blog/posts/mysql-perf-openssl355-evaluation.html">Read more...</a> (19 min remaining to read)</p></div>]]></content:encoded>
    <pubDate>Wed, 22 Apr 2026 04:50:00 +0000</pubDate>
    <dc:creator>Dimitri Kravtchuk</dc:creator>
    <category>BM</category>
    <category>Connect</category>
    <category>E4</category>
    <category>InnoDB</category>
    <category>Linux</category>
    <category>MySQL</category>
    <category>OCI</category>
    <category>OpenSSL</category>
    <category>Performance</category>
    <category>SSL</category>
    <category>Sysbench</category>
    <category>X9</category>
  </item>

  <item>
    <title>MySQL 9.7.0 LTS Is Now Available: Expanded Community Capabilities and Dynamic Data Masking for Enterprise</title>
    <guid isPermaLink="false">0545301a49bdf80d7400eee3457566ec</guid>
    <link>https://blogs.oracle.com/mysql/mysql-9-7-0-lts-is-now-available-expanded-community-capabilities-and-dynamic-data-masking-for-enterprise</link>
    <description>With MySQL 9.7.0 LTS, MySQL establishes its next long-term support release line, expands key capabilities in Community Edition, and introduces Dynamic Data Masking for Enterprise users. The April releases mark an important milestone for MySQL. With the GA of MySQL 9.7.0 LTS, MySQL moves from the 9.x innovation series to a new Long-Term Support release line. This begins […]</description>
    <pubDate>Tue, 21 Apr 2026 16:00:00 +0000</pubDate>
    <dc:creator>Oracle MySQL Group</dc:creator>
    <category>MySQL</category>
    <category>MySQL Community</category>
    <category>MySQL Enterprise</category>
    <category>News</category>
  </item>

  <item>
    <title>Deploying Cross-Site Replication in Percona Operator for MySQL (PXC)</title>
    <guid isPermaLink="false">https://www.percona.com/?p=43843</guid>
    <link>https://www.percona.com/blog/deploying-cross-site-replication-in-percona-operator-for-mysql-pxc/</link>
    <description>Having a separate DR cluster for production databases is a modern day requirement or necessity for tech and other related businesses that rely heavily on their database systems. Setting up such a [DC -&amp;gt; DR] topology for Percona XtraDB Cluster (PXC), which is a virtually- synchronous cluster, can be a bit challenging in a complex Kubernetes environment.
Here, Percona Operator for MySQL comes in handy, with a minimal number of steps to configure such a topology, which ensures a remote side backup or a disaster recovery solution.
So without taking much time, let’s see how the overall setup and configurations look from a practical standpoint.
 
PXC Cross-Site/Disaster Recovery
 
DC Configuration
1) Here we have a three-node PXC cluster running on the DC side.shell&amp;gt; kubectl get pods -n pxc
NAME                                               READY   STATUS      RESTARTS   AGE
cluster1-haproxy-0                                 2/2     Running     0          23h
cluster1-haproxy-1                                 2/2     Running     0          23h
cluster1-haproxy-2                                 2/2     Running     0          23h
cluster1-pxc-0                                     3/3     Running     0          23h
cluster1-pxc-1                                     3/3     Running     0          7h37m
cluster1-pxc-2                                     3/3     Running     0          7h18m
percona-xtradb-cluster-operator-6756dbf588-vxjxt   1/1     Running     0          24h
xb-backup1-hlz2p                                   0/1     Completed   0          21h
xb-cron-cluster1-fs-pvc-2026480026-372f8-2gfhr     0/1     Completed   0          13h2) There are some configuration options which have to be enabled in a custom resource file[cr.yaml] to allow cross-site replication.

Expose all source PXC nodes so they can be communicated from outside or DR cluster.

expose:
      	enabled: true
      	Type: LoadBalancer

Define a dedicated replication channel and enable the source option.

replicationChannels:
    - name: pxc1_to_pxc2
      isSource: true

Finally, applying the custom resource changes.

shell&amp;gt; kubectl apply -f cr.yaml3) Now we will notice some “EXTERNAL IP” details for each PXC node. This is the endpoint that DR node [cluster1-pxc-0] will use to connect to DC.shell&amp;gt; kubectl get svc
NAME                              TYPE           CLUSTER-IP       EXTERNAL-IP     PORT(S)                                          AGE
cluster1-haproxy                  ClusterIP      34.118.227.249   &amp;lt;none&amp;gt;          3306/TCP,3309/TCP,33062/TCP,33060/TCP,8404/TCP   4h1m
cluster1-haproxy-replicas         ClusterIP      34.118.225.41    &amp;lt;none&amp;gt;          3306/TCP                                         4h1m
cluster1-pxc                      ClusterIP      None             &amp;lt;none&amp;gt;          3306/TCP,33062/TCP,33060/TCP                     4h1m
cluster1-pxc-0                    LoadBalancer   34.118.234.140   34.29.145.138   3306:30425/TCP                                   4h1m
cluster1-pxc-1                    LoadBalancer   34.118.239.132   34.30.233.0     3306:31340/TCP                                   4h1m
cluster1-pxc-2                    LoadBalancer   34.118.236.64    35.225.0.19     3306:30642/TCP                                   4h1m
cluster1-pxc-unready              ClusterIP      None             &amp;lt;none&amp;gt;          3306/TCP,33062/TCP,33060/TCP                     4h1m
percona-xtradb-cluster-operator   ClusterIP      34.118.235.168   &amp;lt;none&amp;gt;          443/TCP                                          4h11mAt this point, we are done with the DC setup. Next, we will take a backup from Source which we later used to build the DR.
 
Backup

Defining access key/secrets to connect to the GCP/S3 bucket.

cat backup-secret-s3.yamlapiVersion: v1
kind: Secret
metadata:
  name: my-cluster-name-backup-s3
type: Opaque
data:
  AWS_ACCESS_KEY_ID: &amp;lt;KEY&amp;gt;
  AWS_SECRET_ACCESS_KEY: &amp;lt;SECRET&amp;gt;

In the custom resource file [cr.yaml] , we also need to define the bucket , secret file and endpoint/region details.

backup:

 storages:
   s3-us-west:
      type: s3
      verifyTLS: true

    s3:
      bucket: &amp;lt;bucket&amp;gt;
      credentialsSecret: my-cluster-name-backup-s3
      region: us-west-2
      endpointUrl: https://storage.googleapis.com…shell&amp;gt; kubectl apply -f cr.yaml

Finally, we can take the backup by creating a [backup.yaml] file with below details.

apiVersion: pxc.percona.com/v1
kind: PerconaXtraDBClusterBackup
metadata:
#  finalizers:
#    - percona.com/delete-backup
  name: backup1
spec:
  pxcCluster: cluster1
  storageName:  s3-us-west…shell&amp;gt; kubectl apply -f cr.yaml

We can verify the successful backup as follows.

kubectl get pxc-backup
NAME      CLUSTER    STORAGE      DESTINATION                                     STATUS      COMPLETED   AGE
backup1   cluster1   s3-us-west   s3://&amp;lt;bucket&amp;gt;/cluster1-2026-04-07-15:55:46-full   Succeeded   125m        127mAs the backup is also ready, we can now move to the DR setup part.
 
DR Configuration
Below we have a similar PXC setup as having in DC in a separate Node/ K8s Cluster.kubectl get pods -n pxc-dr
NAME                                               READY   STATUS      RESTARTS   AGE
cluster1-haproxy-0                                 2/2     Running     0          35h
cluster1-haproxy-1                                 2/2     Running     0          35h
cluster1-haproxy-2                                 2/2     Running     0          35h
cluster1-pxc-0                                     3/3     Running     0          35h
cluster1-pxc-1                                     3/3     Running     0          35h
cluster1-pxc-2                                     3/3     Running     0          35h
percona-xtradb-cluster-operator-6756dbf588-2wc5m   1/1     Running     0          38h
prepare-job-restore1-cluster1-8h4vn                0/1     Completed   0          35h
restore-job-restore1-cluster1-trfg6                0/1     Completed   0          35h
xb-cron-cluster1-fs-pvc-2026480025-372f8-wv6bt     0/1     Completed   0          28h
xb-cron-cluster1-fs-pvc-2026490025-372f8-gxd59     0/1     Completed   0          4h48mFirst, we need to restore the backup on the DR server.

Data Restoration

Here we will create the [backup-secret-s3.yaml] file which contains the GCP/S3 credentials.

apiVersion: v1
kind: Secret
metadata:
  name: my-cluster-name-backup-s3
type: Opaque
data:
  AWS_ACCESS_KEY_ID: &amp;lt;KEY&amp;gt;
  AWS_SECRET_ACCESS_KEY: &amp;lt;SECRET&amp;gt;…shell&amp;gt; kubectl apply -f backup-secret-s3.yaml

Next, we will create a [restore.yaml] file while mentioning the backup source and other useful information.

apiVersion: pxc.percona.com/v1
kind: PerconaXtraDBClusterRestore
metadata:
  name: restore1
#  annotations:
#    percona.com/headless-service: &quot;true&quot;
spec:
  pxcCluster: cluster1
  backupSource:
#    verifyTLS: true
    destination: s3://&amp;lt;bucket&amp;gt;/cluster1-2026-04-07-15:55:46-full
    s3:
      bucket: &amp;lt;bucket&amp;gt;
      credentialsSecret: my-cluster-name-backup-s3
      endpointUrl: https://storage.googleapis.com/…shell&amp;gt; kubectl apply -f restore.yaml

Once the restoration is finished successfully, we will see the status below.

shell&amp;gt; kubectl get pxc-restore
NAME       CLUSTER    STATUS      COMPLETED   AGE
restore1   cluster1   Succeeded               27mNow we can do the remaining DR changes in the custom resource file [cr.yaml]. Basically, we need to add the replication channel and all source EXTERNAL-IPs. This cross-DC replication supports Automatic Asynchronous Replication Connection Failover feature, so in case any of the DC node is down, the Replica can connect and resume from other available DC nodes.replicationChannels:
    - name: pxc1_to_pxc2
      isSource: false
      sourcesList:
      - host: 34.29.145.138  
        port: 3306
        weight: 100

      - host: 34.30.233.0
        port: 3306
        weight: 100

      - host: 35.225.0.19
        port: 3306
        weight: 100…shell&amp;gt; kubectl apply -f cr.yamlFor backup and restoration on the PXC operator, the manuals below can be referenced further.


https://docs.percona.com/percona-operator-for-mysql/pxc/backups-ondemand.html
https://docs.percona.com/percona-operator-for-mysql/pxc/backups-restore-to-new-cluster.html

 
Replication
Initially, when we check the replication status, we can notice the following error. This is because with [caching_sha2_password] authentication, it should be a secure SSL/TLS communication, or else we can use SOURCE_PUBLIC_KEY_PATH/GET_SOURCE_PUBLIC_KEY  which basicaly enables the RSA key pair-based password exchange by requesting the public key from the source. shell&amp;gt; kubectl exec -it cluster1-pxc-0  -- sh
shell&amp;gt; mysql -uroot -pmysql&amp;gt; show replica status\G;
*************************** 1. row ***************************
             Replica_IO_State: Connecting to source
                  Source_Host: 35.225.0.19
                  Source_User: replication
                  Source_Port: 3306
                Connect_Retry: 60
              Source_Log_File: 
          Read_Source_Log_Pos: 4
               Relay_Log_File: cluster1-pxc-0-relay-bin-pxc1_to_pxc2.000001
                Relay_Log_Pos: 4
        Relay_Source_Log_File: 
           Replica_IO_Running: Connecting
          Replica_SQL_Running: Yes
...
Error:
Last_IO_Error: Error connecting to source 'replication@35.225.0.19:3306'. This was attempt 2/3, with a delay of 60 seconds between attempts. Message: Access denied for user 'replication'@'35.225.0.19.' (using password: YES)Once we passed “GET_SOURCE_PUBLIC_KEY” in the “CHANGE REPLICATION” command the  error is resolved and DR successfully able to communicate with the DC.mysql&amp;gt; STOP REPLICA;
mysql&amp;gt; STOP REPLICA IO_THREAD FOR CHANNEL 'pxc1_to_pxc2';
mysql&amp;gt; CHANGE REPLICATION SOURCE TO SOURCE_USER='replication', SOURCE_PASSWORD='password', GET_SOURCE_PUBLIC_KEY=1 FOR CHANNEL 'pxc1_to_pxc2';
mysql&amp;gt; START REPLICA;
Note  – The Replication user will be auto-created on the DC node. So, with the help of below command we can get the decoded password for “replication” user.
shell&amp;gt; kubectl get secret cluster1-secrets -o jsonpath=&quot;{.data.replication}&quot; | base64 --decodemysql&amp;gt; show replica status\G;
*************************** 1. row ***************************
             Replica_IO_State: Waiting for source to send event
                  Source_Host: 35.225.0.19
                  Source_User: replication
                  Source_Port: 3306
                Connect_Retry: 60
              Source_Log_File: binlog.000006
          Read_Source_Log_Pos: 3047027
               Relay_Log_File: cluster1-pxc-0-relay-bin-pxc1_to_pxc2.000001
                Relay_Log_Pos: 150132
        Relay_Source_Log_File: binlog.000006
           Replica_IO_Running: Yes
          Replica_SQL_Running: Yes
...The other PXC DR nodes will sync as usual with the Galera Synchronous replication process. 

Source Failover
The asynchronous connection failover is already enabled on the DR as we defined initially in the custom resource file. The “External IPs”  shows different here because they changed in this testing scenario.mysql&amp;gt; select * from performance_schema.replication_asynchronous_connection_failover;
+--------------+---------------+------+-------------------+--------+--------------+
| CHANNEL_NAME | HOST          | PORT | NETWORK_NAMESPACE | WEIGHT | MANAGED_NAME |
+--------------+---------------+------+-------------------+--------+--------------+
| pxc1_to_pxc2 | 34.29.145.138 | 3306 |                   |    100 |              |
| pxc1_to_pxc2 | 34.45.151.96  | 3306 |                   |    100 |              |
| pxc1_to_pxc2 | 34.71.57.38   | 3306 |                   |    100 |              |
+--------------+---------------+------+-------------------+--------+--------------+
3 rows in set (0.00 sec)Now, in case the existing Source DC[cluster1-pxc-2] is down, the DR will connect to one of the other available DC nodes based on the “Weight” and chronological order [pxc-2, pxc-1, pxc-0 etc].

Here, we temporarily take down the Source DC[cluster1-pxc-2] node.

kubectl get pods -n pxc
NAME                                               READY   STATUS      RESTARTS     AGE
cluster1-haproxy-0                                 2/2     Running     0            2d3h
cluster1-haproxy-1                                 2/2     Running     0            2d3h
cluster1-haproxy-2                                 2/2     Running     0            2d3h
cluster1-pxc-0                                     3/3     Running     0            2d3h
cluster1-pxc-1                                     3/3     Running     0            35h
cluster1-pxc-2                                     2/3     Running     1 (6s ago)   34h
percona-xtradb-cluster-operator-6756dbf588-vxjxt   1/1     Running     0            2d3h
xb-backup1-hlz2p                                   0/1     Completed   0            2d1h
xb-cron-cluster1-fs-pvc-2026480026-372f8-2gfhr     0/1     Completed   0            41h
xb-cron-cluster1-fs-pvc-2026490026-372f8-mgfpv     0/1     Completed   0            17h

The DR replication breaks as it can’t reach the DC [cluster1-pxc-2].

mysql&amp;gt; show replica status\G;
*************************** 1. row ***************************
             Replica_IO_State: Reconnecting after a failed source event read
                  Source_Host: 34.71.57.38
                  Source_User: replication
                  Source_Port: 3306
                Connect_Retry: 60
              Source_Log_File: binlog.000012
          Read_Source_Log_Pos: 198
               Relay_Log_File: cluster1-pxc-0-relay-bin-pxc1_to_pxc2.000002
                Relay_Log_Pos: 369
        Relay_Source_Log_File: binlog.000012
           Replica_IO_Running: Connecting
          Replica_SQL_Running: Yes
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 0
                   Last_Error: 
                 Skip_Counter: 0
          Exec_Source_Log_Pos: 198
              Relay_Log_Space: 602
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Source_SSL_Allowed: No
           Source_SSL_CA_File: 
           Source_SSL_CA_Path: 
              Source_SSL_Cert: 
            Source_SSL_Cipher: 
               Source_SSL_Key: 
        Seconds_Behind_Source: NULL
Source_SSL_Verify_Server_Cert: Yes
                Last_IO_Errno: 2003
                Last_IO_Error: Error reconnecting to source 'replication@34.71.57.38:3306'. This was attempt 2/3, with a delay of 60 seconds between attempts. Message: Can't connect to MySQL server on '34.71.57.38:3306' (111)

Once it reaches the “source_retry_count” and “source_connect_retry”, the Replica connects to another Source DC[cluster1-pxc-1].

mysql&amp;gt; show replica status\G;
*************************** 1. row ***************************
             Replica_IO_State: Waiting for source to send event
                  Source_Host: 34.45.151.96
                  Source_User: replication
                  Source_Port: 3306
                Connect_Retry: 60
              Source_Log_File: binlog.000007
          Read_Source_Log_Pos: 198
               Relay_Log_File: cluster1-pxc-0-relay-bin-pxc1_to_pxc2.000003
                Relay_Log_Pos: 369
        Relay_Source_Log_File: binlog.000007
           Replica_IO_Running: Yes
          Replica_SQL_Running: Yes
...

Quick Summary
In this blog post, we walk through the steps to configure Cross-Site Replication in the Percona PXC operator. Although we have used the operator native Xtrabackup to feed the data to the DR via the restore process, we can also use logical backup options like (mysqldump, mydumper, etc.) to accomplish the same goals. 
Using an “Asynchronous Replication” process to sync DR could lead to delays or replication lag due to its flow, or, more importantly, when working across data centres, where network latency is a big factor. However, adding a DR(PXC) cluster to DC(PXC) directly via synchronous replication could be more impactful or lead to flow control issues if any of the DR nodes struggle or experience performance/saturation issues. So, it’s equally important to consider all aspects or challenges before deploying in production.
The post Deploying Cross-Site Replication in Percona Operator for MySQL (PXC) appeared first on Percona.</description>
    <content:encoded><![CDATA[<p><span>Having a separate DR cluster for production databases is a modern day requirement or necessity for tech and other related businesses that rely heavily on their database systems. Setting up such a [DC -&gt; DR] topology for Percona XtraDB Cluster (PXC), which is a virtually- synchronous cluster, can be a bit challenging in a complex Kubernetes environment.</span></p>
<p><span>Here, Percona Operator for MySQL comes in handy, with a minimal number of steps to configure such a topology, which ensures a remote side backup or a disaster recovery solution.</span></p>
<p><span>So without taking much time, let’s see how the overall setup and configurations look from a practical standpoint.</span></p>
<p> </p>
<figure aria-describedby="caption-attachment-43844" class="wp-caption alignnone"><img loading="lazy" decoding="async" class="size-full wp-image-43844" src="https://www.percona.com/wp-content/uploads/2026/04/image1.png" alt="PXC Cross-Site/Disaster Recovery" width="960" height="540" srcset="https://www.percona.com/wp-content/uploads/2026/04/image1.png 960w, https://www.percona.com/wp-content/uploads/2026/04/image1-300x169.png 300w, https://www.percona.com/wp-content/uploads/2026/04/image1-768x432.png 768w" sizes="auto, (max-width: 960px) 100vw, 960px"><figcaption class="wp-caption-text">PXC Cross-Site/Disaster Recovery</figcaption></figure>
<p> </p>
<h2>DC Configuration</h2>
<p><span><span>1) Here we have a three-node PXC cluster running on the DC side.</span></span></p><pre class="urvanov-syntax-highlighter-plain-tag">shell&gt; kubectl get pods -n pxc
NAME                                               READY   STATUS      RESTARTS   AGE
cluster1-haproxy-0                                 2/2     Running     0          23h
cluster1-haproxy-1                                 2/2     Running     0          23h
cluster1-haproxy-2                                 2/2     Running     0          23h
cluster1-pxc-0                                     3/3     Running     0          23h
cluster1-pxc-1                                     3/3     Running     0          7h37m
cluster1-pxc-2                                     3/3     Running     0          7h18m
percona-xtradb-cluster-operator-6756dbf588-vxjxt   1/1     Running     0          24h
xb-backup1-hlz2p                                   0/1     Completed   0          21h
xb-cron-cluster1-fs-pvc-2026480026-372f8-2gfhr     0/1     Completed   0          13h</pre><p><span>2) There are some configuration options which have to be enabled in a custom resource file[cr.yaml] to allow cross-site replication.</span></p>
<ul>
<li aria-level="1"><span>Expose all source PXC nodes so they can be communicated from outside or DR cluster.</span></li>
</ul>
<p></p><pre class="urvanov-syntax-highlighter-plain-tag">expose:
      	enabled: true
      	Type: LoadBalancer</pre><p></p>
<ul>
<li aria-level="1"><span>Define a dedicated replication channel and enable the source option.</span></li>
</ul>
<p></p><pre class="urvanov-syntax-highlighter-plain-tag">replicationChannels:
    - name: pxc1_to_pxc2
      isSource: true</pre><p></p>
<ul>
<li aria-level="1"><span>Finally, applying the custom resource changes.</span></li>
</ul>
<p></p><pre class="urvanov-syntax-highlighter-plain-tag">shell&gt; kubectl apply -f cr.yaml</pre><p><span>3) Now we will notice some</span><b> “EXTERNAL IP”</b><span> details for each PXC node. This is the endpoint that DR node [cluster1-pxc-0] will use to connect to DC.</span></p><pre class="urvanov-syntax-highlighter-plain-tag">shell&gt; kubectl get svc
NAME                              TYPE           CLUSTER-IP       EXTERNAL-IP     PORT(S)                                          AGE
cluster1-haproxy                  ClusterIP      34.118.227.249   &lt;none&gt;          3306/TCP,3309/TCP,33062/TCP,33060/TCP,8404/TCP   4h1m
cluster1-haproxy-replicas         ClusterIP      34.118.225.41    &lt;none&gt;          3306/TCP                                         4h1m
cluster1-pxc                      ClusterIP      None             &lt;none&gt;          3306/TCP,33062/TCP,33060/TCP                     4h1m
cluster1-pxc-0                    LoadBalancer   34.118.234.140   34.29.145.138   3306:30425/TCP                                   4h1m
cluster1-pxc-1                    LoadBalancer   34.118.239.132   34.30.233.0     3306:31340/TCP                                   4h1m
cluster1-pxc-2                    LoadBalancer   34.118.236.64    35.225.0.19     3306:30642/TCP                                   4h1m
cluster1-pxc-unready              ClusterIP      None             &lt;none&gt;          3306/TCP,33062/TCP,33060/TCP                     4h1m
percona-xtradb-cluster-operator   ClusterIP      34.118.235.168   &lt;none&gt;          443/TCP                                          4h11m</pre><p><span>At this point, we are done with the DC setup. Next, we will take a backup from Source which we later used to build the DR.</span></p>
<p> </p>
<h2><span>Backup</span></h2>
<ul>
<li aria-level="1"><span>Defining access key/secrets to connect to the GCP/S3 bucket.</span></li>
</ul>
<p></p><pre class="urvanov-syntax-highlighter-plain-tag">cat backup-secret-s3.yaml</pre><p></p><pre class="urvanov-syntax-highlighter-plain-tag">apiVersion: v1
kind: Secret
metadata:
  name: my-cluster-name-backup-s3
type: Opaque
data:
  AWS_ACCESS_KEY_ID: &lt;KEY&gt;
  AWS_SECRET_ACCESS_KEY: &lt;SECRET&gt;</pre><p></p>
<ul>
<li aria-level="1"><span>In the custom resource file [cr.yaml] , we also need to define the bucket , secret file and endpoint/region details.</span></li>
</ul>
<p></p><pre class="urvanov-syntax-highlighter-plain-tag">backup:

 storages:
   s3-us-west:
      type: s3
      verifyTLS: true

    s3:
      bucket: &lt;bucket&gt;
      credentialsSecret: my-cluster-name-backup-s3
      region: us-west-2
      endpointUrl: https://storage.googleapis.com</pre><p>…</p><pre class="urvanov-syntax-highlighter-plain-tag">shell&gt; kubectl apply -f cr.yaml</pre><p></p>
<ul>
<li aria-level="1"><span>Finally, we can take the backup by creating a [</span><b>backup.yaml]</b><span> file with below details.</span></li>
</ul>
<p></p><pre class="urvanov-syntax-highlighter-plain-tag">apiVersion: pxc.percona.com/v1
kind: PerconaXtraDBClusterBackup
metadata:
#  finalizers:
#    - percona.com/delete-backup
  name: backup1
spec:
  pxcCluster: cluster1
  storageName:  s3-us-west</pre><p>…</p><pre class="urvanov-syntax-highlighter-plain-tag">shell&gt; kubectl apply -f cr.yaml</pre><p></p>
<ul>
<li aria-level="1"><span>We can verify the successful backup as follows.</span></li>
</ul>
<p></p><pre class="urvanov-syntax-highlighter-plain-tag">kubectl get pxc-backup
NAME      CLUSTER    STORAGE      DESTINATION                                     STATUS      COMPLETED   AGE
backup1   cluster1   s3-us-west   s3://&lt;bucket&gt;/cluster1-2026-04-07-15:55:46-full   Succeeded   125m        127m</pre><p><span>As the backup is also ready, we can now move to the DR setup part.</span></p>
<p> </p>
<h2><span>DR Configuration</span></h2>
<p><span>Below we have a similar PXC setup as having in DC in a separate Node/ K8s Cluster.</span></p><pre class="urvanov-syntax-highlighter-plain-tag">kubectl get pods -n pxc-dr
NAME                                               READY   STATUS      RESTARTS   AGE
cluster1-haproxy-0                                 2/2     Running     0          35h
cluster1-haproxy-1                                 2/2     Running     0          35h
cluster1-haproxy-2                                 2/2     Running     0          35h
cluster1-pxc-0                                     3/3     Running     0          35h
cluster1-pxc-1                                     3/3     Running     0          35h
cluster1-pxc-2                                     3/3     Running     0          35h
percona-xtradb-cluster-operator-6756dbf588-2wc5m   1/1     Running     0          38h
prepare-job-restore1-cluster1-8h4vn                0/1     Completed   0          35h
restore-job-restore1-cluster1-trfg6                0/1     Completed   0          35h
xb-cron-cluster1-fs-pvc-2026480025-372f8-wv6bt     0/1     Completed   0          28h
xb-cron-cluster1-fs-pvc-2026490025-372f8-gxd59     0/1     Completed   0          4h48m</pre><p><span>First, we need to restore the backup on the DR server.</span></p>
<h2></h2>
<h2><span>Data Restoration</span></h2>
<ul>
<li aria-level="1"><span>Here we will create the [</span><b>backup-secret-s3.yaml</b><span>] file which contains the GCP/S3 credentials.</span></li>
</ul>
<p></p><pre class="urvanov-syntax-highlighter-plain-tag">apiVersion: v1
kind: Secret
metadata:
  name: my-cluster-name-backup-s3
type: Opaque
data:
  AWS_ACCESS_KEY_ID: &lt;KEY&gt;
  AWS_SECRET_ACCESS_KEY: &lt;SECRET&gt;</pre><p>…</p><pre class="urvanov-syntax-highlighter-plain-tag">shell&gt; kubectl apply -f backup-secret-s3.yaml</pre><p></p>
<ul>
<li aria-level="1"><span>Next, we will create a [</span><b>restore.yaml</b><span>] file while mentioning the backup source and other useful information.</span></li>
</ul>
<p></p><pre class="urvanov-syntax-highlighter-plain-tag">apiVersion: pxc.percona.com/v1
kind: PerconaXtraDBClusterRestore
metadata:
  name: restore1
#  annotations:
#    percona.com/headless-service: "true"
spec:
  pxcCluster: cluster1
  backupSource:
#    verifyTLS: true
    destination: s3://&lt;bucket&gt;/cluster1-2026-04-07-15:55:46-full
    s3:
      bucket: &lt;bucket&gt;
      credentialsSecret: my-cluster-name-backup-s3
      endpointUrl: https://storage.googleapis.com/</pre><p>…</p><pre class="urvanov-syntax-highlighter-plain-tag">shell&gt; kubectl apply -f restore.yaml</pre><p></p>
<ul>
<li aria-level="1"><span>Once the restoration is finished successfully, we will see the status below.</span></li>
</ul>
<p></p><pre class="urvanov-syntax-highlighter-plain-tag">shell&gt; kubectl get pxc-restore
NAME       CLUSTER    STATUS      COMPLETED   AGE
restore1   cluster1   Succeeded               27m</pre><p><span>Now we can do the remaining DR changes in the custom resource file [</span><b>cr.yaml</b><span>]. Basically, we need to add the replication channel and all source EXTERNAL-IPs. This cross-DC replication supports </span><a href="https://dev.mysql.com/doc/refman/8.0/en/replication-asynchronous-connection-failover.html"><span>Automatic Asynchronous Replication Connection Failover feature</span></a><span>, so in case any of the DC node is down, the Replica can connect and resume from other available DC nodes.</span></p><pre class="urvanov-syntax-highlighter-plain-tag">replicationChannels:
    - name: pxc1_to_pxc2
      isSource: false
      sourcesList:
      - host: 34.29.145.138  
        port: 3306
        weight: 100

      - host: 34.30.233.0
        port: 3306
        weight: 100

      - host: 35.225.0.19
        port: 3306
        weight: 100</pre><p>…</p><pre class="urvanov-syntax-highlighter-plain-tag">shell&gt; kubectl apply -f cr.yaml</pre><p>For backup and restoration on the PXC operator, the manuals below can be referenced further.</p>
<blockquote>
<ul>
<li><a href="https://docs.percona.com/percona-operator-for-mysql/pxc/backups-ondemand.html">https://docs.percona.com/percona-operator-for-mysql/pxc/backups-ondemand.html</a></li>
<li><a href="https://docs.percona.com/percona-operator-for-mysql/pxc/backups-restore-to-new-cluster.html">https://docs.percona.com/percona-operator-for-mysql/pxc/backups-restore-to-new-cluster.html</a></li>
</ul>
<p> </p></blockquote>
<h2>Replication</h2>
<p><span>Initially, when we check the replication status, we can notice the following error. This is because with [</span><b>caching_sha2_password</b><span>] authentication, it should be a secure SSL/TLS communication, or else we can use </span><a href="https://dev.mysql.com/doc/refman/9.6/en/change-replication-source-to.html#crs-opt-get_source_public_key"><b>SOURCE_PUBLIC_KEY_PATH</b><span>/</span><b>GET_SOURCE_PUBLIC_KEY</b></a><span>  which basicaly enables the RSA key pair-based password exchange by requesting the public key from the source. </span></p><pre class="urvanov-syntax-highlighter-plain-tag">shell&gt; kubectl exec -it cluster1-pxc-0  -- sh
shell&gt; mysql -uroot -p</pre><p></p><pre class="urvanov-syntax-highlighter-plain-tag">mysql&gt; show replica status\G;
*************************** 1. row ***************************
             Replica_IO_State: Connecting to source
                  Source_Host: 35.225.0.19
                  Source_User: replication
                  Source_Port: 3306
                Connect_Retry: 60
              Source_Log_File: 
          Read_Source_Log_Pos: 4
               Relay_Log_File: cluster1-pxc-0-relay-bin-pxc1_to_pxc2.000001
                Relay_Log_Pos: 4
        Relay_Source_Log_File: 
           Replica_IO_Running: Connecting
          Replica_SQL_Running: Yes
...</pre><p></p>
<h5><b>Error:</b></h5>
<p></p><pre class="urvanov-syntax-highlighter-plain-tag">Last_IO_Error: Error connecting to source 'replication@35.225.0.19:3306'. This was attempt 2/3, with a delay of 60 seconds between attempts. Message: Access denied for user 'replication'@'35.225.0.19.' (using password: YES)</pre><p><span>Once we passed “</span><b>GET_SOURCE_PUBLIC_KEY” </b><span>in the</span><b> “CHANGE REPLICATION” </b><span>command</span> <span>the  error is resolved and DR successfully able to communicate with the DC.</span></p><pre class="urvanov-syntax-highlighter-plain-tag">mysql&gt; STOP REPLICA;
mysql&gt; STOP REPLICA IO_THREAD FOR CHANNEL 'pxc1_to_pxc2';
mysql&gt; CHANGE REPLICATION SOURCE TO SOURCE_USER='replication', SOURCE_PASSWORD='password', GET_SOURCE_PUBLIC_KEY=1 FOR CHANNEL 'pxc1_to_pxc2';
mysql&gt; START REPLICA;</pre><p></p>
<h5><b>Note</b><span>  – The Replication user will be auto-created on the DC node. So, with the help of below command we can get the decoded password for “</span><b>replication</b><span>” user.</span></h5>
<p></p><pre class="urvanov-syntax-highlighter-plain-tag">shell&gt; kubectl get secret cluster1-secrets -o jsonpath="{.data.replication}" | base64 --decode</pre><p></p><pre class="urvanov-syntax-highlighter-plain-tag">mysql&gt; show replica status\G;
*************************** 1. row ***************************
             Replica_IO_State: Waiting for source to send event
                  Source_Host: 35.225.0.19
                  Source_User: replication
                  Source_Port: 3306
                Connect_Retry: 60
              Source_Log_File: binlog.000006
          Read_Source_Log_Pos: 3047027
               Relay_Log_File: cluster1-pxc-0-relay-bin-pxc1_to_pxc2.000001
                Relay_Log_Pos: 150132
        Relay_Source_Log_File: binlog.000006
           Replica_IO_Running: Yes
          Replica_SQL_Running: Yes
...</pre><p><span>The other PXC DR nodes will sync as usual with the Galera Synchronous replication process. </span></p>
<h2></h2>
<h2><span>Source Failover</span></h2>
<p><span>The asynchronous connection failover is already enabled on the DR as we defined initially in the custom resource file. The “External IPs”  shows different here because they changed in this testing scenario.</span></p><pre class="urvanov-syntax-highlighter-plain-tag">mysql&gt; select * from performance_schema.replication_asynchronous_connection_failover;
+--------------+---------------+------+-------------------+--------+--------------+
| CHANNEL_NAME | HOST          | PORT | NETWORK_NAMESPACE | WEIGHT | MANAGED_NAME |
+--------------+---------------+------+-------------------+--------+--------------+
| pxc1_to_pxc2 | 34.29.145.138 | 3306 |                   |    100 |              |
| pxc1_to_pxc2 | 34.45.151.96  | 3306 |                   |    100 |              |
| pxc1_to_pxc2 | 34.71.57.38   | 3306 |                   |    100 |              |
+--------------+---------------+------+-------------------+--------+--------------+
3 rows in set (0.00 sec)</pre><p><span>Now, in case the existing Source DC[cluster1-pxc-2] is down, the DR will connect to one of the other available DC nodes based on the “Weight” and chronological order [pxc-2, pxc-1, pxc-0 etc].</span></p>
<ul>
<li aria-level="1"><span>Here, we temporarily take down the Source DC[cluster1-pxc-2] node.</span></li>
</ul>
<p></p><pre class="urvanov-syntax-highlighter-plain-tag">kubectl get pods -n pxc
NAME                                               READY   STATUS      RESTARTS     AGE
cluster1-haproxy-0                                 2/2     Running     0            2d3h
cluster1-haproxy-1                                 2/2     Running     0            2d3h
cluster1-haproxy-2                                 2/2     Running     0            2d3h
cluster1-pxc-0                                     3/3     Running     0            2d3h
cluster1-pxc-1                                     3/3     Running     0            35h
cluster1-pxc-2                                     2/3     Running     1 (6s ago)   34h
percona-xtradb-cluster-operator-6756dbf588-vxjxt   1/1     Running     0            2d3h
xb-backup1-hlz2p                                   0/1     Completed   0            2d1h
xb-cron-cluster1-fs-pvc-2026480026-372f8-2gfhr     0/1     Completed   0            41h
xb-cron-cluster1-fs-pvc-2026490026-372f8-mgfpv     0/1     Completed   0            17h</pre><p></p>
<ul>
<li aria-level="1"><span>The DR replication breaks as it can’t reach the DC [cluster1-pxc-2].</span></li>
</ul>
<p></p><pre class="urvanov-syntax-highlighter-plain-tag">mysql&gt; show replica status\G;
*************************** 1. row ***************************
             Replica_IO_State: Reconnecting after a failed source event read
                  Source_Host: 34.71.57.38
                  Source_User: replication
                  Source_Port: 3306
                Connect_Retry: 60
              Source_Log_File: binlog.000012
          Read_Source_Log_Pos: 198
               Relay_Log_File: cluster1-pxc-0-relay-bin-pxc1_to_pxc2.000002
                Relay_Log_Pos: 369
        Relay_Source_Log_File: binlog.000012
           Replica_IO_Running: Connecting
          Replica_SQL_Running: Yes
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 0
                   Last_Error: 
                 Skip_Counter: 0
          Exec_Source_Log_Pos: 198
              Relay_Log_Space: 602
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Source_SSL_Allowed: No
           Source_SSL_CA_File: 
           Source_SSL_CA_Path: 
              Source_SSL_Cert: 
            Source_SSL_Cipher: 
               Source_SSL_Key: 
        Seconds_Behind_Source: NULL
Source_SSL_Verify_Server_Cert: Yes
                Last_IO_Errno: 2003
                Last_IO_Error: Error reconnecting to source 'replication@34.71.57.38:3306'. This was attempt 2/3, with a delay of 60 seconds between attempts. Message: Can't connect to MySQL server on '34.71.57.38:3306' (111)</pre><p></p>
<ul>
<li aria-level="1"><span>Once it reaches the “</span><b>source_retry_count”</b><span> and “</span><b>source_connect_retry”,</b><span> the Replica connects to another Source DC[cluster1-pxc-1].</span></li>
</ul>
<p></p><pre class="urvanov-syntax-highlighter-plain-tag">mysql&gt; show replica status\G;
*************************** 1. row ***************************
             Replica_IO_State: Waiting for source to send event
                  Source_Host: 34.45.151.96
                  Source_User: replication
                  Source_Port: 3306
                Connect_Retry: 60
              Source_Log_File: binlog.000007
          Read_Source_Log_Pos: 198
               Relay_Log_File: cluster1-pxc-0-relay-bin-pxc1_to_pxc2.000003
                Relay_Log_Pos: 369
        Relay_Source_Log_File: binlog.000007
           Replica_IO_Running: Yes
          Replica_SQL_Running: Yes
...</pre><p></p>
<h2></h2>
<h2><span>Quick Summary</span></h2>
<p><span>In this blog post, we walk through the steps to configure <a href="https://docs.percona.com/percona-operator-for-mysql/pxc/replication.html#system-user-for-replication">Cross-Site Replication in the Percona PXC operator</a>. Although we have used the operator native Xtrabackup to feed the data to the DR via the restore process, we can also use logical backup options like (mysqldump, mydumper, etc.) to accomplish the same goals. </span></p>
<p><span>Using an “Asynchronous Replication” process to sync DR could lead to delays or replication lag due to its flow, or, more importantly, when working across data centres, where network latency is a big factor. However, adding a DR(PXC) cluster to DC(PXC) directly via synchronous replication could be more impactful or lead to flow control issues if any of the DR nodes struggle or experience performance/saturation issues. So, it’s equally important to consider all aspects or challenges before deploying in production.</span></p>
<p>The post <a href="https://www.percona.com/blog/deploying-cross-site-replication-in-percona-operator-for-mysql-pxc/">Deploying Cross-Site Replication in Percona Operator for MySQL (PXC)</a> appeared first on <a href="https://www.percona.com/">Percona</a>.</p>]]></content:encoded>
    <pubDate>Mon, 20 Apr 2026 13:15:04 +0000</pubDate>
    <dc:creator>MySQL Performance Blog</dc:creator>
    <category>Cloud</category>
    <category>Database Trends</category>
    <category>Featured</category>
    <category>Insight for DBAs</category>
    <category>Insight for Developers</category>
    <category>Kubernetes</category>
    <category>MySQL</category>
    <category>Open Source</category>
    <category>Operator</category>
    <category>Percona Services</category>
    <category>Percona Software</category>
    <category>Storage Engine</category>
    <category>Uncategorized</category>
    <category>High Availability</category>
    <category>high availability with asynchronous replication</category>
    <category>InnoDB</category>
    <category>insight fo</category>
  </item>

  <item>
    <title>MySQL MCP Server v1.7.0 is out</title>
    <guid isPermaLink="false">http://askdba.net/?p=2895</guid>
    <link>https://askdba.net/2026/04/20/mysql-mcp-server-v1-7-0-is-out/</link>
    <description>April 19, 2026



It took three release candidates and more CI tweaks than I’d like to admit, but v1.7.0 is finally tagged GA. Here’s what actually changed and why it matters.







The thing I kept getting asked about: add_connection



Almost every multi-database user hits the same wall: you configure your connections at startup, and that’s it. Want to point Claude at a different instance mid-session? Restart the server. Not great.



add_connection fixes that. Enable it with MYSQL_MCP_EXTENDED=1 and MYSQL_MCP_ENABLE_ADD_CONNECTION=1, and Claude can register a new named connection on the fly — DSN validation, duplicate-name rejection, and a hard block on the root MySQL user all happen before the connection is accepted. Once it’s in, use_connection it works as usual.



It’s intentionally opt-in behind two flags. Allowing an AI client to register arbitrary database connections at runtime warrants an explicit “yes, I want this” from the operator.







Finding stuff across a big schema: search_schema and schema_diff



Two tools I personally felt the absence of every time I was debugging a large schema.



search_schema does what it sounds like — pattern-match against table and column names across all accessible databases. Before this, you’d either write the query yourself or ask Claude to guess where a column lived. Now you just ask.



schema_diff is the one I’m more excited about. Point it at two databases, and it tells you what’s structurally different. Columns that exist in staging but not prod, type mismatches, missing indexes — all surface immediately. We’ve already caught more than a few “oh, that migration never ran” moments with it.







Pagination, retries, and the unglamorous stuff



run_query now supports an offset parameter for SELECT and UNION queries, returning has_more and next_offset in the response. Big result sets no longer mean hitting row caps and wondering what you missed.



Retries got a proper implementation too. Transient errors — bad pooled connections, deadlocks, lock wait timeouts — now trigger exponential backoff instead of just failing. After a driver.ErrBadConn the pool is re-pinged, which cuts recovery time noticeably after a MySQL restart.



Neither of these is flashy, but they’re the kind of thing that makes the tool feel solid rather than fragile.







Column masking



Set MYSQL_MCP_MASK_COLUMNS=email,password,ssn and those columns are redacted in every run_query response. Nothing leaves the server. No query rewrites, no application changes. It’s a small feature that a few teams have been asking for since before v1.6.







One breaking change worth knowing about: SSH host key verification



This one could bite you on upgrade if you’re using SSH tunnels. Host key verification is now on by default. The tunnel checks ~/.ssh/known_hosts (or MYSQL_SSH_KNOWN_HOSTS, or a pinned MYSQL_SSH_HOST_KEY_FINGERPRINT) before allowing the connection.



If you were running without strict host key checking, your tunnel will fail after upgrading until you either add the host key to known_hosts or explicitly opt out with MYSQL_SSH_STRICT_HOST_KEY_CHECKING=false. The opt-out exists, but it’s a MITM risk — the default is the right behavior.







Upgrading



	
		
			

# Homebrewbrew update &amp;amp;&amp;amp; brew upgrade mysql-mcp-server# Dockerdocker pull ghcr.io/askdba/mysql-mcp-server:latest
		
	



Full changelog: github.com/askdba/mysql-mcp-server/releases/tag/v1.7.0



Questions and issues are welcome on GitHub.



</description>
    <content:encoded><![CDATA[<p class="wp-block-paragraph"><em>April 19, 2026</em></p>



<p class="wp-block-paragraph">It took three release candidates and more CI tweaks than I’d like to admit, but v1.7.0 is finally tagged GA. Here’s what actually changed and why it matters.</p>



<hr class="wp-block-separator has-alpha-channel-opacity">



<h2 class="wp-block-heading">The thing I kept getting asked about: <code>add_connection</code></h2>



<p class="wp-block-paragraph">Almost every multi-database user hits the same wall: you configure your connections at startup, and that’s it. Want to point Claude at a different instance mid-session? Restart the server. Not great.</p>



<p class="wp-block-paragraph"><code>add_connection</code> fixes that. Enable it with <code>MYSQL_MCP_EXTENDED=1</code> and <code>MYSQL_MCP_ENABLE_ADD_CONNECTION=1</code>, and Claude can register a new named connection on the fly — DSN validation, duplicate-name rejection, and a hard block on the <code>root</code> MySQL user all happen before the connection is accepted. Once it’s in, <code>use_connection</code> it works as usual.</p>



<p class="wp-block-paragraph">It’s intentionally opt-in behind two flags. Allowing an AI client to register arbitrary database connections at runtime warrants an explicit “yes, I want this” from the operator.</p>



<hr class="wp-block-separator has-alpha-channel-opacity">



<h2 class="wp-block-heading">Finding stuff across a big schema: <code>search_schema</code> and <code>schema_diff</code></h2>



<p class="wp-block-paragraph">Two tools I personally felt the absence of every time I was debugging a large schema.</p>



<p class="wp-block-paragraph"><code>search_schema</code> does what it sounds like — pattern-match against table and column names across all accessible databases. Before this, you’d either write the query yourself or ask Claude to guess where a column lived. Now you just ask.</p>



<p class="wp-block-paragraph">schema_diff is the one I’m more excited about. Point it at two databases, and it tells you what’s structurally different. Columns that exist in staging but not prod, type mismatches, missing indexes — all surface immediately. We’ve already caught more than a few “oh, that migration never ran” moments with it.</p>



<hr class="wp-block-separator has-alpha-channel-opacity">



<h2 class="wp-block-heading">Pagination, retries, and the unglamorous stuff</h2>



<p class="wp-block-paragraph"><code>run_query</code> now supports an <code>offset</code> parameter for SELECT and UNION queries, returning <code>has_more</code> and <code>next_offset</code> in the response. Big result sets no longer mean hitting row caps and wondering what you missed.</p>



<p class="wp-block-paragraph">Retries got a proper implementation too. Transient errors — bad pooled connections, deadlocks, lock wait timeouts — now trigger exponential backoff instead of just failing. After a <code>driver.ErrBadConn</code> the pool is re-pinged, which cuts recovery time noticeably after a MySQL restart.</p>



<p class="wp-block-paragraph">Neither of these is flashy, but they’re the kind of thing that makes the tool feel solid rather than fragile.</p>



<hr class="wp-block-separator has-alpha-channel-opacity">



<h2 class="wp-block-heading">Column masking</h2>



<p class="wp-block-paragraph">Set <code>MYSQL_MCP_MASK_COLUMNS=email,password,ssn</code> and those columns are redacted in every <code>run_query</code> response. Nothing leaves the server. No query rewrites, no application changes. It’s a small feature that a few teams have been asking for since before v1.6.</p>



<hr class="wp-block-separator has-alpha-channel-opacity">



<h2 class="wp-block-heading">One breaking change worth knowing about: SSH host key verification</h2>



<p class="wp-block-paragraph">This one could bite you on upgrade if you’re using SSH tunnels. Host key verification is now <strong>on by default</strong>. The tunnel checks <code>~/.ssh/known_hosts</code> (or <code>MYSQL_SSH_KNOWN_HOSTS</code>, or a pinned <code>MYSQL_SSH_HOST_KEY_FINGERPRINT</code>) before allowing the connection.</p>



<p class="wp-block-paragraph">If you were running without strict host key checking, your tunnel will fail after upgrading until you either add the host key to <code>known_hosts</code> or explicitly opt out with <code>MYSQL_SSH_STRICT_HOST_KEY_CHECKING=false</code>. The opt-out exists, but it’s a MITM risk — the default is the right behavior.</p>



<hr class="wp-block-separator has-alpha-channel-opacity">



<h2 class="wp-block-heading">Upgrading</h2>


<div class="wp-block-code">
	<div class="cm-editor">
		<div class="cm-scroller">
			
<pre>
<code><div class="cm-line"># Homebrew</div><div class="cm-line">brew update &amp;&amp; brew upgrade mysql-mcp-server</div><div class="cm-line"></div><div class="cm-line"># Docker</div><div class="cm-line">docker pull ghcr.io/askdba/mysql-mcp-server:latest</div><div class="cm-line"></div></code></pre>
		</div>
	</div>
</div>


<p class="wp-block-paragraph">Full changelog: <a href="https://github.com/askdba/mysql-mcp-server/releases/tag/v1.7.0">github.com/askdba/mysql-mcp-server/releases/tag/v1.7.0</a></p>



<p class="wp-block-paragraph">Questions and issues are welcome on GitHub.</p>



<p class="wp-block-paragraph"></p>]]></content:encoded>
    <pubDate>Sun, 19 Apr 2026 21:00:38 +0000</pubDate>
    <dc:creator>Alkin Tezuysal</dc:creator>
    <category>mysql</category>
    <category>Technical</category>
    <category>ai</category>
    <category>artificial-intelligence</category>
    <category>llm</category>
    <category>mcp</category>
    <category>technology</category>
  </item>

</channel>
</rss>
