<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
  xmlns:content="http://purl.org/rss/1.0/modules/content/"
  xmlns:wfw="http://wellformedweb.org/CommentAPI/"
  xmlns:dc="http://purl.org/dc/elements/1.1/"
  xmlns:atom="http://www.w3.org/2005/Atom"
  xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
  xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
  >
<channel>
  <title>MariaDB.org-Planet-Feed</title>
  <atom:link href="https://mariadb.org/planet-rss" rel="self" type="application/rss+xml"/>
  <link>https://mariadb.org/?page_id=24734</link>
  <description>Supporting continuity and open collaboration</description>
  <lastBuildDate>Thu, 04 Jun 2026 11:42:04 +0000</lastBuildDate>
  <language></language>
  <sy:updatePeriod>hourly</sy:updatePeriod>
  <sy:updateFrequency>1</sy:updateFrequency>
        <item>
      <title>The Power Of The Community!</title>
      <link>https://mariadb.org/the-power-of-the-community/</link>
      <pubDate>Thu, 04 Jun 2026 11:42:04 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.org/">MariaDB.org</source>
      <description><![CDATA[<p>A proper comparison of the distinct committers to MariaDB and MySQL repositories since Q1 2025.<br />
The post The Power Of The Community! appeared first on MariaDB.org.</p>
<p>The post <a rel="nofollow" href="https://mariadb.org/the-power-of-the-community/">The Power Of The Community!</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>A proper comparison of the distinct committers to MariaDB and MySQL repositories since Q1 2025.</p>
<p>The post <a rel="nofollow" href="https://mariadb.org/the-power-of-the-community/">The Power Of The Community!</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>

<p>The post <a rel="nofollow" href="https://mariadb.org/the-power-of-the-community/">The Power Of The Community!</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Why Modern Finance Runs on Open Source</title>
      <link>https://www.percona.com/blog/why-modern-finance-runs-on-open-source/</link>
      <pubDate>Thu, 04 Jun 2026 10:59:30 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://www.percona.com/blog/">Blog - Percona</source>
      <description><![CDATA[<p>For decades, financial institutions have relied on proprietary databases to power everything from customer transactions to real-time risk engines. But the pressures facing banks, fintechs, and payment providers have changed. Even minutes of downtime can trigger customer loss. 91% of enterprises report costs over $300,000 per hour, with 44% saying it can exceed $1 million. … Continued<br />
The post Why Modern Finance Runs on Open Source appeared first on Percona.</p>
<p>The post <a rel="nofollow" href="https://www.percona.com/blog/why-modern-finance-runs-on-open-source/">Why Modern Finance Runs on Open Source</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>For decades, financial institutions have relied on proprietary databases to power everything from customer transactions to real-time risk engines. But the pressures facing banks, fintechs, and payment providers have changed.</p>
<p>Even minutes of downtime can trigger customer loss. <a href="https://itic-corp.com/tag/hourly-cost-of-downtime/">91% of enterprises</a> report costs over $300,000 per hour, with 44% saying it can exceed $1 million.</p>
<p>At this level of operational risk, databases must scale predictably and adapt quickly. Proprietary databases often work against that goal. Escalating licensing fees, usage-based pricing, and long-term vendor lock-in make it harder to tune performance, expand capacity, or respond to incidents without compounding cost and complexity.</p>
<p>This is why open-source databases have become a core part of modernization efforts across banks, fintechs, and payment platforms. They help keep costs predictable as performance, security, and regulatory demands continue to rise.</p>
<h2>The Financial Industry Is Under Pressure Like Never Before<a class="anchor-link" id="the-financial-industry-is-under-pressure-like-never-before"></a></h2>
<p>Financial institutions are facing unprecedented pressure, putting legacy systems under strain and impacting performance, costs, and compliance.</p>
<h3>Regulatory Expectations Keep Rising<a class="anchor-link" id="regulatory-expectations-keep-rising"></a></h3>
<p>Rising regulatory expectations demand continuous auditing and compliance with PCI DSS, GDPR, AML/ATF, and ESG standards. Complete transparency, high security, and verifiable controls are no longer negotiable.</p>
<p>The proprietary databases introduce friction, since closed architectures and licensing controls restrict the disclosure that regulators require.</p>
<h3>Customers Expect Real-Time Performance<a class="anchor-link" id="customers-expect-real-time-performance"></a></h3>
<p>Even brief transaction delays or outages trigger immediate loss of trust, especially as fintechs set the benchmark for instant, failure-proof experiences. Traditional release cycles and weekend maintenance windows no longer match customer tolerance.</p>
<h3>AI and Data Growth Exceed Traditional Limits<a class="anchor-link" id="ai-and-data-growth-exceed-traditional-limits"></a></h3>
<p>AI workloads and high-dimensional data pipelines drive unprecedented data volume, outpacing the capacity of legacy systems. The rising pressure is translating into growing data center spending, which is predicted to reach <a href="https://www.networkworld.com/article/3820973/data-center-spending-to-top-1-trillion-by-2029-as-ai-transforms-infrastructure.html">$1 trillion</a> in 2029, largely driven by these workloads.</p>
<h3>Legacy and Proprietary Systems Stall Modernization<a class="anchor-link" id="legacy-and-proprietary-systems-stall-modernization"></a></h3>
<p>Vendor-controlled databases slow deployment pipelines, restrict architectural flexibility, and inflate Total Cost of Ownership (TCO) as estates grow more fragmented. Teams lose velocity as they navigate outdated scaling constraints, rigid licensing, and operational silos.</p>
<h2>The Real Constraint: Proprietary Databases and Vendor Lock-In<a class="anchor-link" id="the-real-constraint-proprietary-databases-and-vendor-lock-in"></a></h2>
<p>Even as financial institutions modernize, proprietary databases remain a source of costly, rigid constraints that hinder real progress. Let&rsquo;s see how these constraints surface in practice.</p>
<h3>Licensing Costs that Rise Faster than Value<a class="anchor-link" id="licensing-costs-that-rise-faster-than-value"></a></h3>
<p>Proprietary licensing has quietly become a structural tax on modernization.</p>
<ul>
<li>Rising license fees without added capability directly slow innovation.</li>
<li>Compliance-critical features like encryption, auditing, and high availability (HA) are locked behind premium tiers, driving TCO far above infrastructure costs.</li>
</ul>
<p>When Redis shifted to a more restrictive license, the market reaction was immediate. <a href="https://www.percona.com/blog/redis-users-want-a-change/">Nearly 75% of Redis users began exploring alternatives</a>, and over three-quarters were already testing or migrating to new options.</p>
<p>For financial institutions with regulatory, uptime, and AI requirements, this goes beyond cost and starts to limit long-term decisions.</p>
<h3>Features Locked Behind Enterprise Tiers<a class="anchor-link" id="features-locked-behind-enterprise-tiers"></a></h3>
<p>Compliance and security are typically offered as premium add-ons rather than standard features. Multi-layer encryption, detailed auditing, enterprise HA, and reliable backup may require costly upgrades. Maintaining baseline security and regulatory standards can drive unexpected spending.</p>
<p>In contrast, modern open-source databases come with many of these features built in or easily added, giving institutions more control instead of leaving it with the vendor.</p>
<h3>Forced Upgrades and Migration Penalties<a class="anchor-link" id="forced-upgrades-and-migration-penalties"></a></h3>
<p>Closed licensing gives vendors control over upgrade timing and support windows, not the institutions that run the risk. Forced version jumps and commercial changes rarely align with project roadmaps or risk calendars.</p>
<p>In financial services, where planned change is itself a control, this loss of autonomy introduces unnecessary operational and regulatory exposure.</p>
<h3>Limited Portability Across Hybrid and Multi-Cloud<a class="anchor-link" id="limited-portability-across-hybrid-and-multi-cloud"></a></h3>
<p><a href="https://www.sciencedirect.com/science/article/abs/pii/S0167404825002883">Hybrid and multi-cloud</a> have become standard operating models in finance. But proprietary engines often resist movement across regions, providers, or Kubernetes platforms.</p>
<p>That immobility limits options for latency optimization, data sovereignty, and disaster recovery patterns, exactly where many institutions need the most freedom.</p>
<h3>DBaaS Convenience That Turns Into Runaway Spend<a class="anchor-link" id="dbaas-convenience-that-turns-into-runaway-spend"></a></h3>
<p>A managed proprietary DBaaS looks attractive at first. However, at scale, the economics often flip. Percona&rsquo;s analysis shows that over <a href="https://www.percona.com/blog/alternatives-to-cloud-dbaas-what-to-look-for/">74%</a> of DBaaS users cite high and unpredictable costs as their top challenge, a direct result of opaque, usage-based pricing models.</p>
<p>The institutions encounter uncertain costs on IOPS, storage, backups, cross-region traffic, and autoscaling decisions that they have no full control over.</p>
<p>Financial institutions should not rent out their data infrastructure on conditions that may shift unexpectedly to remain competitive. That need for control, portability, and predictability is what&rsquo;s driving the industry toward open source.</p>
<h2>Why Open Source Has Become the Strategic Advantage in Finance<a class="anchor-link" id="why-open-source-has-become-the-strategic-advantage-in-finance"></a></h2>
<p>With the global open source database market projected to reach USD 63.48 billion by 2034, more and more financial institutions are recognizing its strategic value. Open source now gives them the control, transparency, and flexibility that proprietary databases can&rsquo;t match.</p>
<p><img decoding="async" loading="lazy" class="alignnone wp-image-48689 size-full" src="https://www.percona.com/wp-content/uploads/2026/06/Open-Source-Database-Market.png" alt="Open-Source-Database-Market" width="1291" height="805"></p>
<p style="text-align: center">Open Source Database Market Size | <a href="https://market.us/report/open-source-database-market/"><span style="font-weight: 400">Source</span></a></p>
<p>Let&rsquo;s look at why open source now leads in every dimension that matters.</p>
<h3>Cost Control with Predictable Economics<a class="anchor-link" id="cost-control-with-predictable-economics"></a></h3>
<p>The shift to open source begins with transparency. Where proprietary vendors raise licensing fees and monetize basic compliance features, open source removes artificial cost ceilings and aligns spend with real usage. This includes:</p>
<ul>
<li>No per-core or edition-based licensing</li>
<li>No penalties for scaling read replicas or adding environments</li>
<li>No enterprise tier required for auditing, encryption, or HA</li>
</ul>
<p>Open source restores <a href="https://learn.percona.com/hubfs/eBooks/Fixing-Data-Slowdowns-Without-Breaking-the-Bank.pdf">financial governance</a> and eliminates unexpected cost shocks as data volumes grow. This gives organizations predictable economics and control over their database spending.</p>
<h3>Scalability Without Constraint<a class="anchor-link" id="scalability-without-constraint"></a></h3>
<p>Open source scales with <a href="https://www.percona.com/blog/open-source-vs-proprietary-software">demand</a>, not with licensing policy. In high-volume trading or high payment flow periods, capacity can grow vertically or horizontally without precipitating premium editions, replica fees, or per-core uplifts.</p>
<p>Cloud-native automation strengthens elasticity across regions, clouds, and Kubernetes environments. It enables scale-out patterns that follow real workload behavior instead of vendor-driven architecture choices.</p>
<p>This saves the IOPS taxes, network surcharges, and hard-and-fast capacity levels that often bloat proprietary DBaaS prices.</p>
<h3>Security and Compliance Through Transparency<a class="anchor-link" id="security-and-compliance-through-transparency"></a></h3>
<p>Financial institutions need to demonstrate every control they implement. Proprietary databases make this challenging because their security mechanisms cannot be inspected or validated.</p>
<p>Open source removes this barrier by giving teams full visibility into how security controls and safeguards function. That clarity sets the foundation for the capabilities that follow:</p>
<ul>
<li>Native encryption at rest, in transit, and at granular data levels</li>
<li>Robust role-based access control (RBAC) and deep auditing frameworks, such as <a href="https://www.pgaudit.org/">pgAudit</a></li>
<li>Configurable policies mapped to PCI DSS, GDPR, AML/ATF, and ESG standards</li>
</ul>
<p>As regulatory pressure accelerates, this transparency becomes essential. Institutions strengthen compliance, reduce licensing costs, and avoid security features locked behind enterprise editions.</p>
<h3>High Availability and Uptime You Can Design, Not Inherit<a class="anchor-link" id="high-availability-and-uptime-you-can-design-not-inherit"></a></h3>
<p>Financial institutions cannot tolerate unpredictable failover behavior. Open source gives architects full control over HA/DR strategy, rather than relying on opaque vendor-managed mechanisms. This includes:</p>
<ul>
<li>Synchronous and asynchronous replication</li>
<li>Multi-region and multi&ndash;data center architectures</li>
<li>Automated failover without black-box dependencies</li>
<li>The ability to tune HA for latency, cost, or regulatory constraints</li>
</ul>
<p>HA is not a feature to buy but an architecture you can design with open source.</p>
<h3>Modernization and Innovation at Enterprise Scale<a class="anchor-link" id="modernization-and-innovation-at-enterprise-scale"></a></h3>
<p>Modern platforms require modular, API driven, cloud native systems. Open source databases integrate naturally into:</p>
<ul>
<li>Cloud-native automation and Kubernetes</li>
<li>CI/CD pipelines to deliver features faster</li>
<li>Asynchronous architectures</li>
<li>Telemetry and ML streams</li>
</ul>
<p>Proprietary databases slow modernization by restricting portability, enforcing rigid architectures, and complicating automation. Open source removes these barriers and gives teams the freedom to experiment and move quickly.</p>
<h3>Talent and Ecosystem Alignment<a class="anchor-link" id="talent-and-ecosystem-alignment"></a></h3>
<p>Open source tooling is widely embraced by developers, SREs, architects, and data engineers, as it aligns seamlessly with how modern teams build, test, and scale software. This includes:</p>
<ul>
<li>Larger talent pools for PostgreSQL, MySQL, MongoDB, and cloud-native ecosystems</li>
<li>Faster internal development cycles</li>
<li>Higher retention and a more collaborative engineering culture</li>
</ul>
<p>Open source isn&rsquo;t simply a cheaper alternative, it is structurally aligned with how modern financial institutions operate. It provides the control, visibility, scalability, and freedom needed to compete in a market of data, AI, compliance, and relentless uptime requirements.</p>
<h2>Making Open Source Enterprise-Grade: Where Percona Fits In<a class="anchor-link" id="making-open-source-enterprise-grade-where-percona-fits-in"></a></h2>
<p>Open source provides financial institutions with flexibility and cost control. <a href="https://docs.percona.com/">Percona</a> turns that foundation into an operationally mature, secure, high-availability data platform suitable for regulated, always-on financial workloads.</p>
<h3>Unified Multi-Database Expertise<a class="anchor-link" id="unified-multi-database-expertise"></a></h3>
<p>Financial systems commonly use multiple data engines, MySQL for transactions, PostgreSQL for analytics, MongoDB for document storage, and more. Percona supports this diversity through a single engineering organization, offering:</p>
<ul>
<li>Full production&#8209;grade support for MySQL, PostgreSQL, and MongoDB via <a href="https://www.percona.com/software/percona-operators">Percona&rsquo;s distributions</a>.</li>
<li>Cross&#8209;engine expertise in performance, indexing, replication, and <a href="https://docs.percona.com/percona-toolkit/pt-online-schema-change.html">schema</a> strategies.</li>
<li>An integrable observability layer through <a href="https://experience.percona.com/postgresql/monitoring-and-management/">Percona Monitoring and Management (PMM)</a>, with the ability to monitor and control all your supported engines on a single dashboard.</li>
</ul>
<p>This unified approach gives financial institutions a consistent, reliable way to operate diverse database environments at scale.</p>
<h3>Enterprise-Ready Open Source Software<a class="anchor-link" id="enterprise-ready-open-source-software"></a></h3>
<p>Percona&rsquo;s database distributions take community editions and enhance them with features and defaults tuned for enterprise production:</p>
<ul>
<li><a href="https://www.percona.com/postgresql">Percona&rsquo;s PostgreSQL distribution</a> offers enterprise&#8209;ready security and high availability with no licensing fees or hidden add-ons.</li>
<li>Performance optimizations and configuration tuning beyond stock community defaults.</li>
<li>High&#8209;availability automation, backup and recovery workflows (including point-in-time recovery), replication/sharding, and automated cluster scaling.</li>
</ul>
<p>This means financial teams can run open&#8209;source databases with the predictability, operational rigor, and enterprise-grade features often associated with commercial editions.</p>
<h3>24&times;7&times;365 Support Built for Critical Financial System<a class="anchor-link" id="24x7x365-support-built-for-critical-financial-system"></a></h3>
<p>Percona keeps your databases online:</p>
<ul>
<li><a href="https://www.percona.com/software/percona-operators">Operators automate</a> backups, scaling, upgrades, and HA.</li>
<li>PMM offers a single-source monitoring, alerting, and management of MySQL, PostgreSQL, or MongoDB, on-prem, in the cloud, or both.</li>
<li>Live <a href="https://www.percona.com/services/support">tracking and assistance</a> during trading periods, settlement hours, or compliance timelines.</li>
</ul>
<h3>Security and Operational Governance<a class="anchor-link" id="security-and-operational-governance"></a></h3>
<p>Percona ensures open source works within your compliance framework:</p>
<ul>
<li>Traceability (MongoDB, MySQL) through audit logging.</li>
<li>Data encryption in transit and at rest.</li>
<li>Fixed configuration defaults that are consistent with the industry best practices.</li>
<li>Recommendations on how to combine database security with <a href="https://docs.percona.com/percona-server-for-mongodb/6.0/aws-iam.html">identity access management (IAM)</a> and security information and event management (SIEM) systems.</li>
</ul>
<h3>Modernization and Vendor-Exit Expertise<a class="anchor-link" id="modernization-and-vendor-exit-expertise"></a></h3>
<p>Percona helps organizations modernize by migrating from proprietary databases to fully open-source solutions with minimal disruption:</p>
<ul>
<li>Complete open-source using MySQL, <a href="https://experience.percona.com/postgresql/enterprise-postgresql-buyers-guide/3-paying-a-premium-for-security-features-postgresql-includes-for-free">PostgreSQL</a>, and MongoDB.</li>
<li>On-prem, cloud, hybrid, and multi-cloud elastic deployments.</li>
<li>Maintain control over cost, compliance, and performance without lock-in to vendors.</li>
</ul>
<h2>Proof in Action: Financial Institutions Winning With Open Source<a class="anchor-link" id="proof-in-action-financial-institutions-winning-with-open-source"></a></h2>
<p>Modern financial institutions are already succeeding with open-source data infrastructures built and supported by Percona. Their results show what&rsquo;s possible when open-source databases are engineered, observed, and operated at enterprise scale.</p>
<ul>
<li><strong>Payments platforms:</strong> <a href="https://www.percona.com/customer-story/merchant-warrior-counts-on-percona-for-critical-availability/">Merchant Warrior</a> uses Percona for critical MySQL availability and resilience, supporting millions of transactions across 30,000+ customers. Percona XtraDB Cluster and PMM enable the team to have real-time insights and enterprise-level performance without downtime.</li>
<li><strong>Fintech and trading platforms:</strong> Fiserv implemented hybrid MongoDB, MySQL, and PostgreSQL clusters using Percona with ultra-low latency and performance of microseconds on key loads. This shows the efficiency of open-source software in helping financial platforms scale and maintain rigorous SLAs.</li>
<li><strong>Credit unions / digital banks:</strong> With Percona Server, <a href="https://www.percona.com/customer-story/bbva-migrates-document-oriented-database-nosql-workloads-to-percona-avoiding-license-costs-and-lock-in/">BBVA</a> moved over 80 applications and 35TB of MongoDB data. This reduced license fees, improved backup performance by 20%, and gave full control over its enterprise database strategy.</li>
<li><strong>Critical applications and cost savings:</strong> Protectall reduced escalating database costs and improved reliability by migrating from MySQL Enterprise to Percona Server. The team then partnered with Percona again to plan a long-term PostgreSQL migration that supports future growth.</li>
</ul>
<h2>What&rsquo;s Next: Take Control With Open Source<a class="anchor-link" id="whats-next-take-control-with-open-source"></a></h2>
<p>Open source is now the backbone of modern financial infrastructure. When your organization is struggling with increasing costs, modernization pressure, compliance problems, or vendor lock-in, it is time to take charge.</p>
<p>Upgrade your databases with <a href="https://www.percona.com/">Percona</a>, achieve enterprise-grade support, predictable costs, and operational control with <a href="https://www.percona.com/mysql/software">MySQL</a>, <a href="https://www.percona.com/postgresql/software/">PostgreSQL</a>, and <a href="https://www.percona.com/mongodb/software/">MongoDB</a>.</p>
<p>The future of finance is open source. Discover how institutions are reducing costs, ensuring compliance, and driving innovation.</p>
<p>The post <a href="https://www.percona.com/blog/why-modern-finance-runs-on-open-source/">Why Modern Finance Runs on Open Source</a> appeared first on <a href="https://www.percona.com">Percona</a>.</p>

<p>The post <a rel="nofollow" href="https://www.percona.com/blog/why-modern-finance-runs-on-open-source/">Why Modern Finance Runs on Open Source</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>What You’re Really Paying for With Proprietary Databases</title>
      <link>https://www.percona.com/blog/what-youre-really-paying-for-with-proprietary-databases/</link>
      <pubDate>Thu, 04 Jun 2026 10:58:39 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://www.percona.com/blog/">Blog - Percona</source>
      <description><![CDATA[<p>On paper, proprietary database licensing looks simple. You look at a predictable per-core licensing cost, the estimated infrastructure spend, and the support contract. But the actual cost of a proprietary database is not a line item. The predictability dissolves once workloads grow, new services are launched, or regulatory and uptime demands force you to scale … Continued<br />
The post What You’re Really Paying for With Proprietary Databases appeared first on Percona.</p>
<p>The post <a rel="nofollow" href="https://www.percona.com/blog/what-youre-really-paying-for-with-proprietary-databases/">What You’re Really Paying for With Proprietary Databases</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>On paper, proprietary database licensing looks simple. You look at a predictable per-core licensing cost, the estimated infrastructure spend, and the support contract.</p>
<p>But the actual cost of a proprietary database is not a line item. The predictability dissolves once workloads grow, new services are launched, or regulatory and uptime demands force you to scale aggressively. The bill shows up later as add-ons, markups, and architectural limitations that quietly shape every strategic decision.</p>
<p>Proprietary databases are rarely evaluated on the total <a href="https://learn.percona.com/cp-enterprise-tco-reduce-your-total-cost-of-ownership">cost of ownership</a> across five to ten years. Instead, they are justified as a necessary platform cost, even as their pricing, restrictions, and lock-in reduce your ability to modernize, migrate to the cloud, or optimize for AI and new products. Actually, you don&rsquo;t just pay for the database. You pay for the way it constrains your options.</p>
<p>This article explains the Total Cost of Ownership (TCO) of proprietary databases, detailing the architectural, operational, and strategic burdens they impose beyond the initial price.</p>
<h2>License fees are just the entry price<a class="anchor-link" id="license-fees-are-just-the-entry-price"></a></h2>
<p>Most proprietary databases start with a base license model, per-core, per-processor, per-socket, or tied to specific instance sizes and regions in the cloud.</p>
<p>As soon as you scale out (more nodes, more replicas, more environments) or scale up (more powerful instances), your licensing footprint expands, even if business value grows more slowly than technical capacity.</p>
<p>Tiered pricing forces expensive upgrades for critical features, such as <a href="https://www.percona.com/blog/transparent-data-encryption-tde/">Transparent Data Encryption (TDE)</a>, granular <a href="https://www.percona.com/sites/default/files/ple19-slides/ple19-PCI-DSS-Compliance-with-MySQL-2019-Edition.pdf">PCI-DSS</a> auditing, or <a href="https://www.percona.com/blog/the-ultimate-guide-to-database-high-availability/">active-active High Availability (HA)</a>.</p>
<p>Cloud database services add another layer by bundling license, compute, storage, and management into opaque service tiers with markups that can exceed <a href="https://www.percona.com/blog/managed-database-vs-kubernetes-taking-back-control-of-your-cloud-costs-and-agility/">80&ndash;100%</a> of the underlying infrastructure cost.</p>
<p>What looked like simple all-in pricing at proof of concept becomes a permanent premium as you scale across regions, add failover zones, and support 24&times;7 workloads.</p>
<p>Put simply, the license is just the entry ticket; the real spending kicks in as you grow.</p>
<h2>Cost #1: Lock-in limits your options<a class="anchor-link" id="cost-1-lock-in-limits-your-options"></a></h2>
<p>Lock-in is a financial and strategic cost. Proprietary databases encourage deep reliance on vendor-specific extensions, APIs, drivers, and management tooling that make migrations complex and risky.</p>
<p>Over time, these dependencies become embedded in application logic, operational runbooks, and compliance documentation, and raise the exit cost every year.&#8203;</p>
<p>This lock-in becomes visible precisely when you need maximum flexibility:</p>
<ul>
<li>Cloud strategy shifts (moving from single-cloud to multi-cloud or hybrid) expose how hard it is to re-platform proprietary workloads. Many financial institutions are pursuing multi-cloud or hybrid strategies to meet regulatory requirements (<a href="https://www.eiopa.europa.eu/digital-operational-resilience-act-dora_en">DORA in Europe</a>).</li>
<li>Mergers and acquisitions create duplicate database estates that cannot be consolidated easily because of incompatible vendors and licensing models.</li>
<li>Cost-cutting mandates force leadership to accept high database spend because the transition cost is perceived as even higher.</li>
</ul>
<p>Going open-source becomes a viable alternative. Open source databases keep leverage on your side by using standard interfaces and portable architectures. So you can adjust infrastructure, cloud providers, and operating models without rewriting your core.</p>
<p>Percona&rsquo;s <strong>multi-vendor expertise</strong> across MySQL, PostgreSQL, MongoDB, and others is designed to preserve that flexibility while still delivering enterprise-grade support.</p>
<h2>Cost #2: Performance tuning becomes a paid feature<a class="anchor-link" id="cost-2-performance-tuning-becomes-a-paid-feature"></a></h2>
<p>Many proprietary platforms offer advanced observability, query analytics, and tuning tools that are available through separate licenses, packs, or cloud add-ons. And you have to pay extra just to monitor what your database is doing in production, right when performance issues, slowdowns, or outages are already affecting your customers. The paradox is that you end up spending more only after the system has already proven to be inadequate.</p>
<p>That model creates a reactive financial posture. Instead of having 24/7 transparency, organizations find themselves &ldquo;unlocking&rdquo; features only after a crisis has already occurred. You end up rewarding the vendor with more revenue because their system proved inadequate for your current workload.</p>
<p>On the other hand, open source tooling such as <a href="https://www.percona.com/software/database-tools/percona-monitoring-and-management">Percona Monitoring and Management (PMM)</a> provides deep query-level visibility, historical performance data, and health checks as part of an open, community-accessible stack.</p>
<p>You are not charged more for insight, you gain observability by default and can invest in expertise rather than feature unlocks.</p>
<h2>Cost #3: Scaling means paying twice<a class="anchor-link" id="cost-3-scaling-means-paying-twice"></a></h2>
<p>When you scale a proprietary database, you pay twice, once for the underlying infrastructure and again for the licenses tied to that infrastructure. Processor-based licensing or per-core licensing means that adding capacity for peak trading days, new AI scoring models, or additional test environments increases software costs.</p>
<p>This occurs even if revenue per transaction does not grow at the same rate. More cores and nodes do not necessarily represent proportional business value, but they do represent proportional license spend.&#8203;</p>
<p>In cloud DBaaS models, markups and tier structure amplify this effect. Typical high-availability PostgreSQL workloads can <a href="https://www.percona.com/resources/save-on-public-dbaas-costs">cost more than 100% more on proprietary DBaaS</a> than on open-source deployments on Kubernetes or self-managed infrastructure.</p>
<p>Efficient architectures, read replicas, multi-region setups, and extra capacity for resilience are effectively punished by higher recurring bills rather than rewarded for robustness.</p>
<p>With Percona&rsquo;s open source approach, organizations scale for performance and resilience without paying the double tax of proprietary licensing and cloud markups.</p>
<h2>Cost #4: Support that&rsquo;s aligned to the vendor, not you<a class="anchor-link" id="cost-4-support-thats-aligned-to-the-vendor-not-you"></a></h2>
<p>Vendor support is usually positioned as an insurance policy, but its incentives are aligned with renewals rather than with the fastest or most cost-effective solution for your team.</p>
<p>Support SLAs tend to focus on product availability and incident response boundaries rather than on end-to-end business outcomes or architectural improvements. When the &ldquo;right&rdquo; answer is to reduce dependence on premium features, simplify architecture, or migrate off the platform entirely, vendor support has little incentive to champion that path.&#8203;</p>
<p>But in contrast, support that is database-agnostic and open source&ndash;oriented can recommend changes across engines and environments, even when that reduces your spend with any given vendor.</p>
<p><a href="https://www.percona.com/services/managed-services">Percona&rsquo;s support model</a> is built on cross-engine expertise and outcome-focused services such as performance tuning, HA design, and root-cause analysis, rather than upselling proprietary options or new editions. The goal is to optimize your environment, not your license stack.</p>
<h2>Cost #5: Operational inflexibility<a class="anchor-link" id="cost-5-operational-inflexibility"></a></h2>
<p>Proprietary ecosystems often include tightly coupled tooling such as backup utilities, monitoring dashboards, deployment frameworks, and security controls that work with that vendor&rsquo;s stack.</p>
<p>And over time, this creates tool sprawl and operational silos. It necessitates separate processes for different proprietary databases, such as one for Oracle and another for SQL Server, and distinct runbooks for each cloud-specific DBaaS.</p>
<p>Teams spend more time working around tool boundaries than improving reliability, which prevents standardized operations across environments. Change management, incident response, and compliance reporting have to accommodate multiple incompatible systems, increasing training overhead and the risk of errors.</p>
<p>With open source and vendor-neutral tooling such as PMM and <a href="https://www.percona.com/kuberentes-database-report">Kubernetes-based operators</a>, organizations can standardize how they deploy, monitor, and secure databases while preserving the freedom to choose engines and clouds. Operations become unified without forcing a single proprietary vendor everywhere.</p>
<h2>The hidden risk: Strategic decisions get harder over time<a class="anchor-link" id="the-hidden-risk-strategic-decisions-get-harder-over-time"></a></h2>
<p>The considerable cost of proprietary databases is that they can leave companies stuck. The longer they remain on proprietary systems, the harder it becomes to make strategic choices.</p>
<ul>
<li>Budget uncertainty: Sudden changes in licensing terms, such as shifting from perpetual to subscription or changing virtualization rules, can blow a hole in a digital transformation budget overnight.</li>
<li>Innovation blockers: If every new microservice triggers a new enterprise database license discussion, your developers will stop proposing new services. Innovation is stifled by procurement friction.</li>
<li>Long-term planning: When the database is a black box, you cannot accurately predict how it will behave under the next generation of AI workloads, which leads to a conservative, often slower roadmap execution.</li>
</ul>
<h2>What open source changes (when done right)<a class="anchor-link" id="what-open-source-changes-when-done-right"></a></h2>
<p>Open source changes the cost through removing artificial constraints and making pricing a function of infrastructure and expertise instead of vendor permissions.</p>
<p>Organizations pay for compute, storage, and operational skills to run databases like MySQL, PostgreSQL, or MongoDB, not per-core licenses or premium features. It ensures costs are predictable and scale with actual usage, not licensing thresholds.</p>
<p>Open source databases also maximize:</p>
<ul>
<li><strong>Freedom of movement:</strong> Move across clouds (<a href="https://www.percona.com/blog/percona-on-the-aws-database-blog/">AWS</a>, <a href="https://www.percona.com/blog/google-cloud-platform-mysql-at-scale-with-reliable-ha-webinar-qa/">GCP</a>, <a href="https://www.percona.com/blog/embrace-the-cloud-with-microsoft-azure/">Azure</a>), environments (VMs, Containers), and distributions without asking for permission or renegotiating a contract.</li>
<li><strong>Full visibility:</strong> Open source gives your <a href="https://www.percona.com/blog/the-most-important-skills-for-an-sre-dbre-or-dba/">SREs</a> and architects the ability to &ldquo;look under the hood,&rdquo; leading to faster root-cause analysis and more resilient systems.</li>
</ul>
<p>But open source alone is not enough. Execution, architecture design, performance tuning, HA/DR planning, and day-two operations determine whether open source remains a cost advantage or becomes a different kind of complexity.</p>
<h2>Where Percona fits in<a class="anchor-link" id="where-percona-fits-in"></a></h2>
<p>Percona bridges the gap between the freedom of open source and the security requirements of modern finance. Its distributions for <a href="https://www.percona.com/mysql/support-and-services">MySQL</a>, <a href="https://www.percona.com/postgresql/software">PostgreSQL</a>, and <a href="https://www.percona.com/mongodb/software">MongoDB</a> upgrade community editions for production with security, HA integrations, backup/restore, and performance tuning built in. Companies gain top-level capabilities without layered licensing fees or edition gates.&#8203;</p>
<p>Percona also provides:</p>
<ul>
<li><a href="https://www.percona.com/services/support">24&times;7 support</a> and consulting across multiple engines and environments (on-prem, cloud, Kubernetes). Focused on minimizing downtime and optimizing TCO rather than expanding proprietary footprint.</li>
<li><a href="https://percona.community/blog/2023/03/06/monitor-your-databases-with-open-source-tools-like-pmm/">Open observability through PMM</a> to give teams a single place to monitor and manage all supported databases with full transparency and no per-node monitoring tax.&#8203;</li>
</ul>
<p>Simply put, Percona reduces long-term database spend by aligning services with customer outcomes, availability, performance, and cost control.</p>
<h2>Conclusion: Pay for control, not constraints<a class="anchor-link" id="conclusion-pay-for-control-not-constraints"></a></h2>
<p>Proprietary databases promise certainty but can create dependence. They offer predictable costs in the short term but often lead to long-term limitations and increasing markups. Open source databases, when used and managed properly, shift the focus from restrictions to options by letting you use your budget to buy infrastructure, skills, and flexibility instead of just permission to grow.</p>
<p><strong>The important question is not <em>&ldquo;How much does this license cost this year?&rdquo;</em> but rather <em>&ldquo;What will it cost us to remain flexible over the next five years?&rdquo;</em></strong></p>
<p>With open source <a href="https://www.percona.com/solutions/database-observability-monitoring-and-management">databases supported by Percona</a>, financial institutions can answer that question with confidence since they are paying for control and options, not restrictions.</p>
<p>The post <a href="https://www.percona.com/blog/what-youre-really-paying-for-with-proprietary-databases/">What You&rsquo;re Really Paying for With Proprietary Databases</a> appeared first on <a href="https://www.percona.com">Percona</a>.</p>

<p>The post <a rel="nofollow" href="https://www.percona.com/blog/what-youre-really-paying-for-with-proprietary-databases/">What You’re Really Paying for With Proprietary Databases</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>MariaDB Hidden Gem: Create Aggregate Function</title>
      <link>https://mariadb.org/mariadb-hidden-gem-create-aggregate-function/</link>
      <pubDate>Thu, 04 Jun 2026 10:35:49 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.org/">MariaDB.org</source>
      <description><![CDATA[<p>Have you ever written a query where the GROUP BY was easy, but the aggregate was the problem?<br />
You know how to group the rows.You know what result you want for each group.But none of the built-in aggregate functions really match your logic. …<br />
Continue reading \"MariaDB Hidden Gem: Create Aggregate Function\"<br />
The post MariaDB Hidden Gem: Create Aggregate Function appeared first on MariaDB.org.</p>
<p>The post <a rel="nofollow" href="https://mariadb.org/mariadb-hidden-gem-create-aggregate-function/">MariaDB Hidden Gem: Create Aggregate Function</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>Have you ever written a query where the GROUP BY was easy, but the aggregate was the problem?<br>
You know how to group the rows.You know what result you want for each group.But none of <a href="https://mariadb.com/docs/server/reference/sql-functions/aggregate-functions">the built-in aggregate functions</a> really match your logic. &hellip; </p>
<p class="link-more"><a href="https://mariadb.org/mariadb-hidden-gem-create-aggregate-function/" class="more-link">Continue reading<span class="screen-reader-text"> &ldquo;MariaDB Hidden Gem: Create Aggregate Function&rdquo;</span></a></p>
<p>The post <a rel="nofollow" href="https://mariadb.org/mariadb-hidden-gem-create-aggregate-function/">MariaDB Hidden Gem: Create Aggregate Function</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>

<p>The post <a rel="nofollow" href="https://mariadb.org/mariadb-hidden-gem-create-aggregate-function/">MariaDB Hidden Gem: Create Aggregate Function</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Celebrating the MariaDB Foundation Sea Lions Champions Nominees</title>
      <link>https://mariadb.org/celebrating-the-mariadb-foundation-sea-lions-champions-nominees/</link>
      <pubDate>Wed, 03 Jun 2026 08:47:26 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.org/">MariaDB.org</source>
      <description><![CDATA[<p>The MariaDB Foundation Sea Lions Champions recognize individuals and organizations that strengthen the MariaDB ecosystem through technical excellence, community leadership, open-source stewardship, ecosystem impact, and real-world adoption. …<br />
Continue reading \"Celebrating the MariaDB Foundation Sea Lions Champions Nominees\"<br />
The post Celebrating the MariaDB Foundation Sea Lions Champions Nominees appeared first on MariaDB.org.</p>
<p>The post <a rel="nofollow" href="https://mariadb.org/celebrating-the-mariadb-foundation-sea-lions-champions-nominees/">Celebrating the MariaDB Foundation Sea Lions Champions Nominees</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>The MariaDB Foundation Sea Lions Champions recognize individuals and organizations that strengthen the MariaDB ecosystem through technical excellence, community leadership, open-source stewardship, ecosystem impact, and real-world adoption. &hellip; </p>
<p class="link-more"><a href="https://mariadb.org/celebrating-the-mariadb-foundation-sea-lions-champions-nominees/" class="more-link">Continue reading<span class="screen-reader-text"> &ldquo;Celebrating the MariaDB Foundation Sea Lions Champions Nominees&rdquo;</span></a></p>
<p>The post <a rel="nofollow" href="https://mariadb.org/celebrating-the-mariadb-foundation-sea-lions-champions-nominees/">Celebrating the MariaDB Foundation Sea Lions Champions Nominees</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>

<p>The post <a rel="nofollow" href="https://mariadb.org/celebrating-the-mariadb-foundation-sea-lions-champions-nominees/">Celebrating the MariaDB Foundation Sea Lions Champions Nominees</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>MariaDB Foundation: Bringing TPC-B Back To Life</title>
      <link>https://mariadb.org/mariadb-foundation-bringing-tpc-b-back-to-life/</link>
      <pubDate>Wed, 03 Jun 2026 01:10:45 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.org/">MariaDB.org</source>
      <description><![CDATA[<p>When I joined Pervasive PSQL, one of the first performance test cases I was introduced to was TPC-B. It was already implemented inside Pervasive PSQL and it quickly became one of the most important tools in my daily work. …<br />
Continue reading \"MariaDB Foundation: Bringing TPC-B Back To Life\"<br />
The post MariaDB Foundation: Bringing TPC-B Back To Life appeared first on MariaDB.org.</p>
<p>The post <a rel="nofollow" href="https://mariadb.org/mariadb-foundation-bringing-tpc-b-back-to-life/">MariaDB Foundation: Bringing TPC-B Back To Life</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>When I joined <a href="https://en.wikipedia.org/wiki/Pervasive_Software">Pervasive PSQL</a>, one of the first performance test cases I was introduced to was <a href="https://www.tpc.org/tpcb/default5.asp">TPC-B</a>. It was already implemented inside <a href="https://en.wikipedia.org/wiki/Pervasive_Software">Pervasive PSQL </a>and it quickly became one of the most important tools in my daily work. &hellip; </p>
<p class="link-more"><a href="https://mariadb.org/mariadb-foundation-bringing-tpc-b-back-to-life/" class="more-link">Continue reading<span class="screen-reader-text"> &ldquo;MariaDB Foundation: Bringing TPC-B Back To Life&rdquo;</span></a></p>
<p>The post <a rel="nofollow" href="https://mariadb.org/mariadb-foundation-bringing-tpc-b-back-to-life/">MariaDB Foundation: Bringing TPC-B Back To Life</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>

<p>The post <a rel="nofollow" href="https://mariadb.org/mariadb-foundation-bringing-tpc-b-back-to-life/">MariaDB Foundation: Bringing TPC-B Back To Life</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>MariaDB Community Server Corrective Releases</title>
      <link>https://mariadb.org/mariadb-community-server-corrective-releases/</link>
      <pubDate>Tue, 02 Jun 2026 19:20:28 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.org/">MariaDB.org</source>
      <description><![CDATA[<p>MariaDB Community Server corrective releases are now available for the currently maintained long-term series. These releases address critical CVEs, and we strongly recommend that all users review the security advisories and upgrade as soon as possible. …<br />
Continue reading \"MariaDB Community Server Corrective Releases\"<br />
The post MariaDB Community Server Corrective Releases appeared first on MariaDB.org.</p>
<p>The post <a rel="nofollow" href="https://mariadb.org/mariadb-community-server-corrective-releases/">MariaDB Community Server Corrective Releases</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>MariaDB Community Server corrective releases are now available for the currently maintained long-term series. These releases address critical CVEs, and we strongly recommend that all users review the security advisories and upgrade as soon as possible. &hellip; </p>
<p class="link-more"><a href="https://mariadb.org/mariadb-community-server-corrective-releases/" class="more-link">Continue reading<span class="screen-reader-text"> &ldquo;MariaDB Community Server Corrective Releases&rdquo;</span></a></p>
<p>The post <a rel="nofollow" href="https://mariadb.org/mariadb-community-server-corrective-releases/">MariaDB Community Server Corrective Releases</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>

<p>The post <a rel="nofollow" href="https://mariadb.org/mariadb-community-server-corrective-releases/">MariaDB Community Server Corrective Releases</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>MariaDB Enterprise Server Q1 2026 Corrective Releases</title>
      <link>https://mariadb.com/resources/blog/mariadb-enterprise-server-q1-2026-corrective-releases/</link>
      <pubDate>Tue, 02 Jun 2026 18:38:08 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.com/">MariaDB</source>
      <description><![CDATA[<p>New corrective maintenance releases for MariaDB Enterprise Server 11.8.6-4, 11.4.10-8, and 10.6.25-22 are now available. Download Now Notable Release Updates […]</p>
<p>The post <a rel="nofollow" href="https://mariadb.com/resources/blog/mariadb-enterprise-server-q1-2026-corrective-releases/">MariaDB Enterprise Server Q1 2026 Corrective Releases</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>New corrective maintenance releases for MariaDB Enterprise Server 11.8.6-4, 11.4.10-8, and 10.6.25-22 are now available. Download Now MariaDB Enterprise Server is an enhanced, hardened and secured version of MariaDB Community Server that delivers enterprise reliability, stability and long-term support as well as greater operational efficiency when it comes to&hellip;</p>
<p><a href="https://mariadb.com/resources/blog/mariadb-enterprise-server-q1-2026-corrective-releases/" rel="nofollow">Source</a></p>

<p>The post <a rel="nofollow" href="https://mariadb.com/resources/blog/mariadb-enterprise-server-q1-2026-corrective-releases/">MariaDB Enterprise Server Q1 2026 Corrective Releases</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>The Percona Community Slack is open — come hang out</title>
      <link>https://percona.community/blog/2026/06/02/percona-community-slack-open/</link>
      <pubDate>Tue, 02 Jun 2026 11:00:00 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://percona.community/blog/">Percona Community Blog - learn about MySQL, MariaDB, PostgreSQL, and MongoDB</source>
      <description><![CDATA[<p>The Percona Community Slack is open — come hang out There’s a new place for the people behind the databases to actually talk to each other.</p>
<p>The post <a rel="nofollow" href="https://percona.community/blog/2026/06/02/percona-community-slack-open/">The Percona Community Slack is open — come hang out</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<h1 id="the-percona-community-slack-is-open--come-hang-out">The Percona Community Slack is open &mdash; come hang out<a class="anchor-link" id="the-percona-community-slack-is-open-come-hang-out"></a></h1>
<p>There&rsquo;s a new place for the people behind the databases to actually talk to each other.</p>
<p>The Percona Community Slack is open. Right now it&rsquo;s one channel &mdash; General &mdash; and that&rsquo;s intentional. It&rsquo;s a place for DBAs, developers, contributors, and database people of all kinds to meet, swap stories, and get to know who else is out there running open source databases for a living. No silos. No sub-channels for every topic. Just a room.</p>
<h2 id="what-its-for">What it&rsquo;s for<a class="anchor-link" id="what-its-for"></a></h2>
<p>Come here to talk shop. Share what you&rsquo;re building, breaking, or fixing. Post about the migration that went sideways, the config that finally clicked, the pager incident you survived. Ask the kind of questions that belong in a conversation rather than a ticket &mdash; &ldquo;how do other people handle X?&rdquo; is exactly the right energy.</p>
<p>It&rsquo;s also where we&rsquo;ll share events we&rsquo;re attending and, when we have tickets or a spare seat, offer them to the community first. If Percona is heading to a conference near you, this is where you&rsquo;ll hear about it. And if you&rsquo;re going somewhere yourself &mdash; a meetup, a conference, a local user group &mdash; tell us. There might be community members nearby who want to meet up.</p>
<p>That&rsquo;s the point, really. Less broadcast, more conversation.</p>
<h2 id="what-its-not-for">What it&rsquo;s not for<a class="anchor-link" id="what-its-not-for"></a></h2>
<p>Technical support questions belong on the <a href="https://forums.percona.com" target="_blank" rel="noopener noreferrer">Percona Community Forums</a>. Forum answers are searchable and don&rsquo;t disappear into scrollback. Percona engineers and experienced community members watch the forums for questions. Your problem is more likely to get a useful answer there &mdash; and it&rsquo;ll help the person who hits the same issue three months from now.</p>
<p>If you post a support question in Slack, expect to be pointed to the forums. That&rsquo;s not a brush-off.</p>
<h2 id="a-few-things-that-make-this-work">A few things that make this work<a class="anchor-link" id="a-few-things-that-make-this-work"></a></h2>
<p><strong>Introduce yourself.</strong> One or two sentences about what you work on and where in the world you are. That&rsquo;s it. You don&rsquo;t need a bio.</p>
<p><strong>Share what you&rsquo;re up to.</strong> An event you&rsquo;re going to, a tool you&rsquo;ve been testing, a war story from production. The low-key post about a thing you just dealt with is exactly what people come here for.</p>
<p><strong>Lurk freely.</strong> You don&rsquo;t have to post to belong. Read, learn, jump in when you have something to say.</p>
<h2 id="the-short-version-of-the-rules">The short version of the rules<a class="anchor-link" id="the-short-version-of-the-rules"></a></h2>
<p>Be the person you&rsquo;d want to share an on-call rotation with.</p>
<p>Treat everyone as a peer. Assume good faith. No harassment. Critique technology on technical merits. Don&rsquo;t cold-DM people with pitches. Keep private things private. If something needs a moderator&rsquo;s attention, DM one directly &mdash; reports stay confidential.</p>
<h2 id="come-in">Come in<a class="anchor-link" id="come-in"></a></h2>
<p>If you&rsquo;re a DBA, a developer, a contributor, or just someone who runs databases and occasionally wants to talk to other people who run databases &mdash; you belong here.</p>
<p><a href="http://percona.slack.com/" target="_blank" rel="noopener noreferrer">Join the Percona Community Slack &rarr;</a></p>

<p>The post <a rel="nofollow" href="https://percona.community/blog/2026/06/02/percona-community-slack-open/">The Percona Community Slack is open — come hang out</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>A New Pull Request Processing Time Record</title>
      <link>https://mariadb.org/a-new-pull-request-processing-time-record/</link>
      <pubDate>Mon, 01 Jun 2026 14:25:33 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.org/">MariaDB.org</source>
      <description><![CDATA[<p>We have a new record average time to process a pull request: 21 days!<br />
Part of my job is following (and trying to improve of course) some key metrics about MariaDB Server pull request processing. …<br />
Continue reading \"A New Pull Request Processing Time Record\"<br />
The post A New Pull Request Processing Time Record appeared first on MariaDB.org.</p>
<p>The post <a rel="nofollow" href="https://mariadb.org/a-new-pull-request-processing-time-record/">A New Pull Request Processing Time Record</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>We have a new record average time to process a pull request: 21 days!<br>
Part of my job is following (and trying to improve of course) some key metrics about MariaDB Server pull request processing. &hellip; </p>
<p class="link-more"><a href="https://mariadb.org/a-new-pull-request-processing-time-record/" class="more-link">Continue reading<span class="screen-reader-text"> &ldquo;A New Pull Request Processing Time Record&rdquo;</span></a></p>
<p>The post <a rel="nofollow" href="https://mariadb.org/a-new-pull-request-processing-time-record/">A New Pull Request Processing Time Record</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>

<p>The post <a rel="nofollow" href="https://mariadb.org/a-new-pull-request-processing-time-record/">A New Pull Request Processing Time Record</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Building Smart Semantic Search using PostgreSQL and pgvector. Case Study &#8211; Part 2 &#8211; Postgres Layer</title>
      <link>https://percona.community/blog/2026/05/31/semantic-search-on-postgresql-part-2/</link>
      <pubDate>Sun, 31 May 2026 11:00:00 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://percona.community/blog/">Percona Community Blog - learn about MySQL, MariaDB, PostgreSQL, and MongoDB</source>
      <description><![CDATA[<p>I’ll explain how I built the Postgres layer for semantic vector search on the Percona Community website: pgvector, chunks, two table modifications, the database schema, how the indexer populates Postgres, and what the SELECT statement looks like during a search.</p>
<p>The post <a rel="nofollow" href="https://percona.community/blog/2026/05/31/semantic-search-on-postgresql-part-2/">Building Smart Semantic Search using PostgreSQL and pgvector. Case Study &#8211; Part 2 &#8211; Postgres Layer</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>I&rsquo;ll explain how I built the <strong>Postgres layer</strong> for semantic vector search on the Percona Community website: pgvector, chunks, two table modifications, the database schema, how the indexer populates Postgres, and <strong>what the SELECT statement looks like during a search</strong>.</p>
<blockquote>
<p><a href="https://percona.community/blog/2026/05/29/semantic-search-on-postgresql-part-1/">Part 1</a>: why semantic search, what&rsquo;s already working on the site, the widget, and an overview of the stack.</p>
</blockquote>
<p><figure>
<img decoding="async" src="https://percona.community/blog/2026/05/search-part-2-postgres-website-search.png" alt="Percona.community website search"></figure>
</p>
<h2 id="architecture">Architecture<a class="anchor-link" id="architecture"></a></h2>
<p>Search runs separately from the website at <strong>search.percona.community</strong>: FastAPI, a background indexer, and PostgreSQL with pgvector are all in a single Docker Compose file. <a href="https://percona.community" target="_blank" rel="noopener noreferrer">percona.community</a> remains static on Hugo and GitHub Pages, it doesn&rsquo;t write directly to the database.</p>
<pre class="mermaid">
flowchart TB
subgraph users["Users"]
direction TB
User(["User"]) --&gt; Widget["Widget &middot; percona.community"]
Admin(["Admin"]) --&gt; Dash["Admin dashboard &middot; /demo"]
Site["Site &middot; RSS + HTML"]
end
subgraph app["Application"]
direction TB
API["FastAPI &middot; search.percona.community"]
Model["nomic-embed-text-v1"]
Worker["Indexer worker"]
API --&gt;|embed query| Model
Model --&gt;|embedding| API
Worker --&gt;|embed chunks| Model
Model --&gt;|embeddings| Worker
end
subgraph data["Database"]
direction TB
DB[("PostgreSQL + pgvector")]
end
Widget --&gt; API
Dash --&gt; API
Site --&gt; Worker
API --&gt;|read vectors &middot; write queue/history| DB
Worker --&gt;|write vectors &middot; read queue| DB
</pre>
<h3 id="search">Search<a class="anchor-link" id="search"></a></h3>
<p>A visitor enters a query into the widget. The widget sends a <code>POST /search</code> request to FastAPI. The service computes the query embedding with nomic with the prefix <code>search_query:</code> and searches for the nearest vectors in Postgres. The widget knows nothing about pgvector, it only receives JSON with links.</p>
<h3 id="admin-dashboard">Admin dashboard<a class="anchor-link" id="admin-dashboard"></a></h3>
<p>On the same FastAPI service I run an admin dashboard at <code>/demo</code>: test queries, search history, a database summary, viewing documents and chunks. The dashboard does not talk to Postgres directly, it only calls the API; the API reads and writes Postgres (<code>search_history</code>, <code>index_queue</code>, search results).</p>
<p><figure>
<img decoding="async" src="https://percona.community/blog/2026/05/search-part-2-postgres-dashboard-status.png" alt="Admin dashboard - Dashboard"></figure>
</p>
<h3 id="indexing">Indexing<a class="anchor-link" id="indexing"></a></h3>
<p>To refresh the index, I click <strong>Start Indexing</strong> in the dashboard, that hits <code>POST /index/start</code>. The same endpoint can be called from outside: a GitHub webhook after a push to the site repo, cron, or curl while debugging. FastAPI enqueues the job in <code>index_queue</code>. A worker in the indexer container picks it up, downloads RSS and HTML from the site, splits text into chunks, computes vectors with nomic (<code>search_document:</code>), and writes to <code>pages</code>, <code>community_nomic</code>, and <code>indexer_runs</code>. The crawl runs in the background and does not block HTTP.</p>
<p><figure>
<img decoding="async" src="https://percona.community/blog/2026/05/search-part-2-postgres-dashboard-index.png" alt="Admin dashboard - Indexing"></figure>
</p>
<p>Important limitation: the indexer and the API must use the same embedding model. The query vector and the vectors in the database must be from the same space, otherwise, cosine similarity doesn&rsquo;t make sense.</p>
<h2 id="pgvector-in-postgres">pgvector in Postgres<a class="anchor-link" id="pgvector-in-postgres"></a></h2>
<p>For semantic search, you don&rsquo;t need an LLM, but an <strong>embedding model</strong>: a string as input, a vector as output. I chose <strong>nomic-embed-text-v1</strong>, 768-dimensional, running via <code>sentence-transformers</code> on the CPU, without a paid API.</p>
<p>I&rsquo;m using <strong><a href="https://docs.percona.com/postgresql/18/index.html" target="_blank" rel="noopener noreferrer">Percona Distribution for PostgreSQL 18</a></strong>, pgvector is already included in the distribution; <code>CREATE EXTENSION vector</code>, and you&rsquo;re done (<a href="https://docs.percona.com/postgresql/18/enable-extensions.html#pgvector" target="_blank" rel="noopener noreferrer">documentation</a>).</p>
<p>The basic structure is a column with <strong>fixed dimensions</strong> for the model:</p>
<div class="code-block">
<div class="code-block__header"><span class="code-block__lang">sql</span><button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-1">
<div class="highlight">
<pre class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">CREATE</span><span class="w"> </span><span class="n">EXTENSION</span><span class="w"> </span><span class="k">IF</span><span class="w"> </span><span class="k">NOT</span><span class="w"> </span><span class="k">EXISTS</span><span class="w"> </span><span class="n">vector</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">CREATE</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="n">chunks</span><span class="w"> </span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">id</span><span class="w"> </span><span class="nb">SERIAL</span><span class="w"> </span><span class="k">PRIMARY</span><span class="w"> </span><span class="k">KEY</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">chunk_text</span><span class="w"> </span><span class="nb">TEXT</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">embedding</span><span class="w"> </span><span class="n">vector</span><span class="p">(</span><span class="mi">768</span><span class="p">)</span><span class="w"> </span><span class="c1">-- exactly 768 under nomic
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">);</span></span></span></code></pre>
</div>
</div>
</div>
<p>In the project, the table is named <code>community_nomic</code>: the prefix <code>community_</code> (site) + the model key <code>nomic</code>. I&rsquo;m setting up a comparison of embedding models: <strong>each</strong> model has <strong>its own</strong> vector table (<code>community_</code>), because the dimensions and embedding spaces are different, so they can&rsquo;t be mixed in a single table. Currently, there is one model in the project, <strong>nomic-embed-text-v1</strong>, 768 dimensions; later, I can add a second table <code>community_</code> and switch the index/API via <code>EMBEDDING_MODEL_KEY</code>.</p>
<p>pgvector compares vectors with several <strong>distance operators</strong>. I search with <strong>cosine distance</strong> (the <code></code> operator in SQL): the smaller the distance, the closer the match. In the widget and API I show <strong>similarity</strong>, not the raw distance, <code>similarity = 1 - distance</code>, so a higher score means a better hit. The operators:</p>
<table>
<thead>
<tr>
<th>Operator</th>
<th>When useful</th>
</tr>
</thead>
<tbody>
<tr>
<td><code></code></td>
<td>L2 (Euclidean)</td>
</tr>
<tr>
<td><code></code></td>
<td>inner product</td>
</tr>
<tr>
<td><code></code></td>
<td><strong>cosine</strong>, my choice for nomic</td>
</tr>
</tbody>
</table>
<p>Simplified search for &ldquo;nearest chunks&rdquo;:</p>
<div class="code-block">
<div class="code-block__header"><span class="code-block__lang">sql</span><button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-2">
<div class="highlight">
<pre class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="n">slug</span><span class="p">,</span><span class="w"> </span><span class="n">chunk_text</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="p">(</span><span class="n">embedding</span><span class="w"> </span><span class="o"></span><span class="w"> </span><span class="err">$</span><span class="n">query_vector</span><span class="p">)</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">score</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">FROM</span><span class="w"> </span><span class="n">community_nomic</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">ORDER</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="n">embedding</span><span class="w"> </span><span class="o"></span><span class="w"> </span><span class="err">$</span><span class="n">query_vector</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">LIMIT</span><span class="w"> </span><span class="mi">20</span><span class="p">;</span></span></span></code></pre>
</div>
</div>
</div>
<p>The threshold in the API is <code>min_score</code> (my default is <strong>0.52</strong>): anything lower is discarded. On beta I tuned this number for a while, the results changed noticeably depending on this single parameter.</p>
<p>To avoid scanning the entire table as the index grows, I set up an <strong>HNSW</strong> index (approximate nearest neighbor search):</p>
<div class="code-block">
<div class="code-block__header"><span class="code-block__lang">sql</span><button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-3">
<div class="highlight">
<pre class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">CREATE</span><span class="w"> </span><span class="k">INDEX</span><span class="w"> </span><span class="k">ON</span><span class="w"> </span><span class="n">community_nomic</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">USING</span><span class="w"> </span><span class="n">hnsw</span><span class="w"> </span><span class="p">(</span><span class="n">embedding</span><span class="w"> </span><span class="n">vector_cosine_ops</span><span class="p">);</span></span></span></code></pre>
</div>
</div>
</div>
<p>At this scale, a separate vector database wasn&rsquo;t necessary, a single Postgres instance handles metadata, vectors, and search.</p>
<h2 id="postgres-in-docker-docker-compose">Postgres in Docker: <code>docker-compose</code><a class="anchor-link" id="postgres-in-docker-docker-compose"></a></h2>
<p>I set up the stack using <strong>Docker Compose</strong>, Postgres, the API, and the indexer are all in containers, with the same setup locally and in production. Production, <strong>EC2 on AWS</strong> (<code>search.percona.community</code>), an ARM instance, using the same <code>docker-compose</code>.</p>
<p>In <code>docker-compose.yml</code>, Postgres on Percona looks like this (on Mac ARM):</p>
<div class="code-block">
<div class="code-block__header"><span class="code-block__lang">yaml</span><button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-4">
<div class="highlight">
<pre class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">postgres</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">percona/percona-distribution-postgresql:18.1-3-arm64</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">environment</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">POSTGRES_USER</span><span class="p">:</span><span class="w"> </span><span class="l">postgres</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">POSTGRES_PASSWORD</span><span class="p">:</span><span class="w"> </span><span class="l">postgres</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">POSTGRES_DB</span><span class="p">:</span><span class="w"> </span><span class="l">community_search</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">ports</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="s2">"5433:5432"</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">volumes</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="l">pgdata:/var/lib/postgresql/data</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="l">./init:/docker-entrypoint-initdb.d</span></span></span></code></pre>
</div>
</div>
</div>
<p>In <code>init/01-enable-pgvector.sql</code>, include only <code>CREATE EXTENSION IF NOT EXISTS vector</code>. If you&rsquo;re developing on <strong>x86</strong>, <strong>use</strong> amd64 in the image tag instead of <code>arm64</code>, see the options in the <a href="https://docs.percona.com/postgresql/18/index.html" target="_blank" rel="noopener noreferrer">Percona documentation</a>. I left <strong>arm64</strong> on both Mac and EC2: the configuration is the same.</p>
<p>I view the tables and data in <strong>pgAdmin</strong>. The <code>pages</code>, <code>community_nomic</code>, and service tables themselves are created when the API and indexer start using <code>ensure_*</code> functions in the code: these are <code>CREATE TABLE IF NOT EXISTS</code> and <code>CREATE INDEX IF NOT EXISTS</code>, not a separate migration directory.</p>
<h2 id="indexing-and-chunking">Indexing and Chunking<a class="anchor-link" id="indexing-and-chunking"></a></h2>
<p>The site doesn&rsquo;t write directly to the database, the database is populated by an <strong>indexer</strong>: a worker fetches RSS and HTML from <a href="https://percona.community" target="_blank" rel="noopener noreferrer">percona.community</a>, splits the text into chunks, computes embeddings, and writes the rows to <code>community_nomic</code> and <code>pages</code>. The widget and API only read what has already been written during searches.</p>
<h3 id="why-chunks">Why Chunks<a class="anchor-link" id="why-chunks"></a></h3>
<p>At first, I tried <strong>a single vector for the entire article</strong>. I quickly ran into three problems:</p>
<ul>
<li>Long text takes longer to encode and consumes more memory;</li>
<li>The model has an input length limit;</li>
<li>a single vector for long text <strong>blurs</strong> the meaning, a query about a specific paragraph doesn&rsquo;t map well to the &ldquo;averaged&rdquo; embedding of the entire article.</li>
</ul>
<p>I settled on a <strong>400-word</strong> window with a <strong>50</strong>-word overlap (<code>chunker.py</code>). Each chunk is a separate line with its own <code>embedding</code>.</p>
<p>The first version of the chunker sliced <strong>only the body</strong> of the article, without the title, author, date, or tags. For queries like &ldquo;articles by a certain author,&rdquo; the results were off: the model saw the text but not the document&rsquo;s context. I added <strong>metadata to each chunk</strong>, a <code>Title / Author / Date / Tags / Type</code> block at the beginning of each fragment before calculating the vector.</p>
<p><figure>
<img decoding="async" src="https://percona.community/blog/2026/05/search-part-2-postgres-dashboard-chunking.png" alt="Admin dashboard - Chunking"></figure>
</p>
<p>When searching, the API finds the closest chunks, but the card shows <strong>the best chunk for the document</strong> (one <code>slug</code>, one card). Without this, a long article would clutter the results with multiple lines.</p>
<h2 id="database-schema-two-revisions-of-the-chunk-tables">Database Schema: Two Revisions of the Chunk Tables<a class="anchor-link" id="database-schema-two-revisions-of-the-chunk-tables"></a></h2>
<p>I revised the chunk storage schema <strong>twice</strong>, and separately added utility tables for background indexing and search logs.</p>
<h3 id="version-1-everything-in-a-single-table">Version 1: Everything in a Single Table<a class="anchor-link" id="version-1-everything-in-a-single-table"></a></h3>
<p>The first working schema was <strong>a single table for all chunks and document information</strong>: each row represented a single article fragment, and it also contained duplicated page metadata (<strong>url, title, author, date, tags, content_type</strong>) along with <code>chunk_text</code> and <code>embedding</code>.</p>
<p>Pros: one <code>INSERT</code>, one <code>SELECT</code>, no joins.</p>
<p>Cons I encountered:</p>
<ul>
<li>one article, dozens of identical copies of title and author;</li>
<li>when updating a page, it&rsquo;s easy to get out of sync (one title in chunk #0, another in chunk #3);</li>
<li>fetching the image and description for the card from <code>chunk_text</code> was unreliable.</li>
</ul>
<p>Conclusion: A <strong>vector layer</strong> and a <strong>card in the UI</strong> serve different purposes.</p>
<p>The code still includes <code>_migrate_chunks_table</code>: when the API and indexer start up (inside <code>ensure_content_table</code>), it drops any extra columns from the chunk table if they are left over from the old prototype.</p>
<h3 id="version-2-pages--community_nomic">Version 2: <code>pages</code> + <code>community_nomic</code><a class="anchor-link" id="version-2-pages-community_nomic"></a></h3>
<p>I split the data into two tables:</p>
<ul>
<li><strong><code>pages</code></strong>, one row per document: url, title, type, author, date, tags, images, description.</li>
<li><strong><code>community_nomic</code></strong>, only chunks: slug, chunk_index, chunk_text, embedding.</li>
</ul>
<p>They are linked by <code>slug</code> (stable key from the URL). Search: find the nearest chunks in <code>community_nomic</code>, assemble the card from <code>pages</code>.</p>
<p>In the admin dashboard I can open any indexed document and see what landed in <code>pages</code> (metadata, image, description) and what text was split into chunks.</p>
<p><figure>
<img decoding="async" src="https://percona.community/blog/2026/05/search-part-2-postgres-dashboard-details.png" alt="Admin dashboard, document details (pages) and chunks"></figure>
</p>
<p>HNSW on <code>community_nomic</code>:</p>
<div class="code-block">
<div class="code-block__header"><span class="code-block__lang">sql</span><button class="code-block__copy" type="button" data-copy-target="codeblock-5" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-5">
<div class="highlight">
<pre class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">CREATE</span><span class="w"> </span><span class="k">INDEX</span><span class="w"> </span><span class="p">...</span><span class="w"> </span><span class="k">ON</span><span class="w"> </span><span class="n">community_nomic</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">USING</span><span class="w"> </span><span class="n">hnsw</span><span class="w"> </span><span class="p">(</span><span class="n">embedding</span><span class="w"> </span><span class="n">vector_cosine_ops</span><span class="p">);</span></span></span></code></pre>
</div>
</div>
</div>
<p>That&rsquo;s why, when switching models, I don&rsquo;t reuse <code>community_nomic</code>; instead, I create a new table and re-index it. A single search query involves vectors from <strong>only one</strong> model, both during indexing and in the API.</p>
<h2 id="indexer-rss-http-and-queue">Indexer: RSS, HTTP, and Queue<a class="anchor-link" id="indexer-rss-http-and-queue"></a></h2>
<p>The indexer is a separate container that crawls <a href="https://percona.community" target="_blank" rel="noopener noreferrer">percona.community</a> and populates the database. It starts with <strong>RSS</strong>, four feeds:</p>
<ul>
<li><a href="https://percona.community/blog/index.xml" target="_blank" rel="noopener noreferrer">blog/index.xml</a></li>
<li><a href="https://percona.community/events/index.xml" target="_blank" rel="noopener noreferrer">events/index.xml</a></li>
<li><a href="https://percona.community/talks/index.xml" target="_blank" rel="noopener noreferrer">talks/index.xml</a></li>
<li><a href="https://percona.community/contributors/index.xml" target="_blank" rel="noopener noreferrer">contributors/index.xml</a></li>
</ul>
<p>RSS feeds contain a title, link, date, author, tags, and often a short description, but <strong>not the full text of the article</strong>. For each entry, I perform an <strong>HTTP GET</strong> on the HTML page and extract the main content (in <code>crawler.py</code>). If the HTML is empty, I fall back to the description from the RSS feed.</p>
<p>The <strong>Index</strong> and <strong>Status</strong> tabs in the dashboard, without them, debugging the crawl and embedding would have been a guessing game.</p>
<p><figure>
<img decoding="async" src="https://percona.community/blog/2026/05/search-part-2-postgres-dashboard-index-running.png" alt="Admin dashboard - Index Running"></figure>
</p>
<p><figure>
<img decoding="async" src="https://percona.community/blog/2026/05/search-part-2-postgres-dashboard-index-history.png" alt="Admin dashboard - Index history"></figure>
</p>
<p><figure>
<img decoding="async" src="https://percona.community/blog/2026/05/search-part-2-postgres-dashboard-index-stats.png" alt="Admin dashboard - Index overview"></figure>
</p>
<h2 id="table-schema">Table Schema<a class="anchor-link" id="table-schema"></a></h2>
<p>All tables are created when the API and indexer start (<code>ensure_*</code> in code, <code>CREATE TABLE IF NOT EXISTS</code>, <code>CREATE INDEX IF NOT EXISTS</code>). There is no separate migrations folder. I don&rsquo;t use foreign keys between search and utility tables: reindexing deletes and re-inserts rows by <code>slug</code>, and the queue tables are only loosely linked.</p>
<h3 id="search-data">Search data<a class="anchor-link" id="search-data"></a></h3>
<p><strong><code>pages</code></strong> and <strong><code>community_nomic</code></strong> are linked by <code>slug</code> (no FK). The indexer writes both; the API reads them on <code>POST /search</code>.</p>
<h4 id="pages">pages</h4>
<p>One row per document.</p>
<table>
<thead>
<tr>
<th>Column</th>
<th>Type</th>
<th>Purpose</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>slug</code></td>
<td>TEXT</td>
<td>primary key, stable key from the URL</td>
</tr>
<tr>
<td><code>url</code></td>
<td>TEXT</td>
<td>canonical link (UNIQUE)</td>
</tr>
<tr>
<td><code>content_type</code></td>
<td>TEXT</td>
<td>blog, event, talk, contributor</td>
</tr>
<tr>
<td><code>title</code></td>
<td>TEXT</td>
<td>card title</td>
</tr>
<tr>
<td><code>date</code></td>
<td>TEXT</td>
<td>publication date from RSS/HTML</td>
</tr>
<tr>
<td><code>author</code></td>
<td>TEXT</td>
<td>author name</td>
</tr>
<tr>
<td><code>tags</code></td>
<td>TEXT[]</td>
<td>tags for search and chunk metadata</td>
</tr>
<tr>
<td><code>image_url</code></td>
<td>TEXT</td>
<td>full image from the site</td>
</tr>
<tr>
<td><code>image_thumb_url</code></td>
<td>TEXT</td>
<td>smaller image for the widget popup</td>
</tr>
<tr>
<td><code>description</code></td>
<td>TEXT</td>
<td>short description for the card</td>
</tr>
<tr>
<td><code>updated_at</code></td>
<td>TIMESTAMPTZ</td>
<td>last time the row was indexed</td>
</tr>
</tbody>
</table>
<h4 id="community_nomic">community_nomic</h4>
<p>Chunks and vectors (table name = site + model key).</p>
<table>
<thead>
<tr>
<th>Column</th>
<th>Type</th>
<th>Purpose</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>id</code></td>
<td>SERIAL</td>
<td>primary key</td>
</tr>
<tr>
<td><code>slug</code></td>
<td>TEXT</td>
<td>link to <code>pages</code></td>
</tr>
<tr>
<td><code>chunk_index</code></td>
<td>INT</td>
<td>chunk position in the document (UNIQUE with <code>slug</code>)</td>
</tr>
<tr>
<td><code>chunk_text</code></td>
<td>TEXT</td>
<td>text passed to the embedding model</td>
</tr>
<tr>
<td><code>embedding</code></td>
<td>vector(768)</td>
<td>nomic vector for cosine search</td>
</tr>
</tbody>
</table>
<h3 id="utility">Utility<a class="anchor-link" id="utility"></a></h3>
<p>Three small tables for indexing and debugging.</p>
<h4 id="index_queue">index_queue</h4>
<p>Pending jobs. Written by the API.</p>
<table>
<thead>
<tr>
<th>Column</th>
<th>Type</th>
<th>Purpose</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>id</code></td>
<td>SERIAL</td>
<td>primary key</td>
</tr>
<tr>
<td><code>created_at</code></td>
<td>TIMESTAMPTZ</td>
<td>when the job was queued</td>
</tr>
<tr>
<td><code>status</code></td>
<td>TEXT</td>
<td>pending, running, done, cancelled</td>
</tr>
<tr>
<td><code>model</code></td>
<td>TEXT</td>
<td>embedding model key (<code>nomic</code>)</td>
</tr>
<tr>
<td><code>feeds</code></td>
<td>TEXT</td>
<td>RSS feed URLs (comma-separated)</td>
</tr>
<tr>
<td><code>crawl_delay</code></td>
<td>FLOAT</td>
<td>pause between HTTP requests (seconds)</td>
</tr>
<tr>
<td><code>limit_per_type</code></td>
<td>INT</td>
<td>cap per content type (partial reindex)</td>
</tr>
<tr>
<td><code>run_id</code></td>
<td>INT</td>
<td><code>indexer_runs.id</code> once the worker starts</td>
</tr>
<tr>
<td><code>cancel_requested</code></td>
<td>BOOLEAN</td>
<td>cancel flag from the dashboard</td>
</tr>
</tbody>
</table>
<h4 id="indexer_runs">indexer_runs</h4>
<p>Crawl progress. Written by the indexer worker.</p>
<table>
<thead>
<tr>
<th>Column</th>
<th>Type</th>
<th>Purpose</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>id</code></td>
<td>SERIAL</td>
<td>primary key</td>
</tr>
<tr>
<td><code>started_at</code></td>
<td>TIMESTAMPTZ</td>
<td>run start</td>
</tr>
<tr>
<td><code>finished_at</code></td>
<td>TIMESTAMPTZ</td>
<td>run end</td>
</tr>
<tr>
<td><code>status</code></td>
<td>TEXT</td>
<td>running, done, error, cancelled</td>
</tr>
<tr>
<td><code>model</code></td>
<td>TEXT</td>
<td>embedding model key</td>
</tr>
<tr>
<td><code>total_docs</code></td>
<td>INT</td>
<td>documents processed</td>
</tr>
<tr>
<td><code>total_chunks</code></td>
<td>INT</td>
<td>chunks written</td>
</tr>
<tr>
<td><code>current_url</code></td>
<td>TEXT</td>
<td>page being crawled</td>
</tr>
<tr>
<td><code>current_doc_num</code></td>
<td>INT</td>
<td>document counter</td>
</tr>
<tr>
<td><code>errors</code></td>
<td>INT</td>
<td>error count</td>
</tr>
<tr>
<td><code>message</code></td>
<td>TEXT</td>
<td>status or error text</td>
</tr>
</tbody>
</table>
<h4 id="search_history">search_history</h4>
<p>Search log. Written by the API on each <code>POST /search</code>.</p>
<table>
<thead>
<tr>
<th>Column</th>
<th>Type</th>
<th>Purpose</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>id</code></td>
<td>SERIAL</td>
<td>primary key</td>
</tr>
<tr>
<td><code>created_at</code></td>
<td>TIMESTAMPTZ</td>
<td>query time</td>
</tr>
<tr>
<td><code>query</code></td>
<td>TEXT</td>
<td>user query</td>
</tr>
<tr>
<td><code>content_type</code></td>
<td>TEXT</td>
<td>filter: all or one type</td>
</tr>
<tr>
<td><code>limit_requested</code></td>
<td>INT</td>
<td>requested result limit</td>
</tr>
<tr>
<td><code>results_count</code></td>
<td>INT</td>
<td>rows returned</td>
</tr>
<tr>
<td><code>chunks_in_index</code></td>
<td>INT</td>
<td>snapshot: chunk count at query time</td>
</tr>
<tr>
<td><code>by_type</code></td>
<td>JSONB</td>
<td>hit counts per content type</td>
</tr>
<tr>
<td><code>prepare_ms</code></td>
<td>REAL</td>
<td>API timing breakdown</td>
</tr>
<tr>
<td><code>model_load_ms</code></td>
<td>REAL</td>
<td>model load time</td>
</tr>
<tr>
<td><code>embed_ms</code></td>
<td>REAL</td>
<td>embedding time</td>
</tr>
<tr>
<td><code>db_ms</code></td>
<td>REAL</td>
<td>Postgres search time</td>
</tr>
<tr>
<td><code>format_ms</code></td>
<td>REAL</td>
<td>JSON formatting time</td>
</tr>
<tr>
<td><code>total_ms</code></td>
<td>REAL</td>
<td>end-to-end time</td>
</tr>
<tr>
<td><code>model</code></td>
<td>TEXT</td>
<td>embedding model key</td>
</tr>
</tbody>
</table>
<h3 id="indexes">Indexes<a class="anchor-link" id="indexes"></a></h3>
<p>Created in the same <code>ensure_*</code> functions as the tables. Besides primary keys and <code>UNIQUE</code> on <code>pages.url</code> and <code>(slug, chunk_index)</code> in <code>community_nomic</code>:</p>
<ul>
<li><strong><code>pages_content_type_idx</code></strong> on <code>content_type</code>, filter by blog / event / talk / contributor in search;</li>
<li><strong><code>community_nomic_embedding_idx</code></strong>, <strong>HNSW</strong> on <code>embedding</code> (<code>vector_cosine_ops</code>); without it, nearest-neighbor search would scan the whole table as chunks grow;</li>
<li><strong><code>community_nomic_slug_idx</code></strong> on <code>slug</code>, delete all chunks for one document on reindex;</li>
<li><strong><code>search_history_created_at_idx</code></strong>, recent queries first in the dashboard History tab.</li>
</ul>
<p><code>index_queue</code> and <code>indexer_runs</code> only have a serial primary key, few rows, a full scan is fine.</p>
<h2 id="how-postgres-responds-to-a-search-query">How Postgres Responds to a Search Query<a class="anchor-link" id="how-postgres-responds-to-a-search-query"></a></h2>
<p>The API receives the query text, computes a vector with nomic (<code>search_query:</code> + text), and runs SQL that finds the nearest chunks and joins row metadata from <code>pages</code>.</p>
<h3 id="the-first-query-was-naive">The First Query Was Naive<a class="anchor-link" id="the-first-query-was-naive"></a></h3>
<p>At first, I did what the pgvector tutorials suggest, &ldquo;find the 20 closest vectors&rdquo;:</p>
<div class="code-block">
<div class="code-block__header"><span class="code-block__lang">sql</span><button class="code-block__copy" type="button" data-copy-target="codeblock-6" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-6">
<div class="highlight">
<pre class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="n">slug</span><span class="p">,</span><span class="w"> </span><span class="n">chunk_index</span><span class="p">,</span><span class="w"> </span><span class="n">chunk_text</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="p">(</span><span class="n">embedding</span><span class="w"> </span><span class="o"></span><span class="w"> </span><span class="err">$</span><span class="n">query_vector</span><span class="p">)</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">score</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">FROM</span><span class="w"> </span><span class="n">community_nomic</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">ORDER</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="n">embedding</span><span class="w"> </span><span class="o"></span><span class="w"> </span><span class="err">$</span><span class="n">query_vector</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">LIMIT</span><span class="w"> </span><span class="mi">20</span><span class="p">;</span></span></span></code></pre>
</div>
</div>
</div>
<p>The query <strong>worked</strong>, but the results were incorrect from a UI perspective. It returns <strong>20 chunks</strong>, not <strong>20 documents</strong>. A long article with fifteen chunks could take up <strong>half the list</strong> with a single <code>slug</code>; a short post with one good paragraph didn&rsquo;t make it to the top. The user sees <strong>pages</strong> (cards with links), but we search the database by <strong>chunks</strong>, I close that gap in SQL.</p>
<h3 id="what-i-do-now">What I do now<a class="anchor-link" id="what-i-do-now"></a></h3>
<ol>
<li><strong>Join</strong> <code>community_nomic</code> + <code>pages</code> by <code>slug</code>.</li>
<li><code>ROW_NUMBER() PARTITION BY slug</code>, I keep <strong>one</strong> best chunk per document.</li>
<li><code>WHERE score &gt;= min_score</code> (default <strong>0.52</strong>).</li>
<li><code>ORDER BY score DESC LIMIT N</code>.</li>
</ol>
<p>Simplified version of the final query:</p>
<div class="code-block">
<div class="code-block__header"><span class="code-block__lang">sql</span><button class="code-block__copy" type="button" data-copy-target="codeblock-7" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-7">
<div class="highlight">
<pre class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">WITH</span><span class="w"> </span><span class="n">ranked</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">SELECT</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">p</span><span class="p">.</span><span class="n">url</span><span class="p">,</span><span class="w"> </span><span class="n">p</span><span class="p">.</span><span class="n">title</span><span class="p">,</span><span class="w"> </span><span class="n">p</span><span class="p">.</span><span class="n">content_type</span><span class="p">,</span><span class="w"> </span><span class="k">c</span><span class="p">.</span><span class="n">slug</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="p">(</span><span class="k">c</span><span class="p">.</span><span class="n">embedding</span><span class="w"> </span><span class="o"></span><span class="w"> </span><span class="err">$</span><span class="n">query_vector</span><span class="p">)</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">score</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">ROW_NUMBER</span><span class="p">()</span><span class="w"> </span><span class="n">OVER</span><span class="w"> </span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">PARTITION</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="k">c</span><span class="p">.</span><span class="n">slug</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">ORDER</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="k">c</span><span class="p">.</span><span class="n">embedding</span><span class="w"> </span><span class="o"></span><span class="w"> </span><span class="err">$</span><span class="n">query_vector</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">)</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">rn</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">community_nomic</span><span class="w"> </span><span class="k">c</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">INNER</span><span class="w"> </span><span class="k">JOIN</span><span class="w"> </span><span class="n">pages</span><span class="w"> </span><span class="n">p</span><span class="w"> </span><span class="k">ON</span><span class="w"> </span><span class="n">p</span><span class="p">.</span><span class="n">slug</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">c</span><span class="p">.</span><span class="n">slug</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="c1">-- AND p.content_type = 'blog' -- optional: filter by type
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="n">best_per_page</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">SELECT</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">ranked</span><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="n">rn</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">SELECT</span><span class="w"> </span><span class="n">url</span><span class="p">,</span><span class="w"> </span><span class="n">title</span><span class="p">,</span><span class="w"> </span><span class="n">content_type</span><span class="p">,</span><span class="w"> </span><span class="n">slug</span><span class="p">,</span><span class="w"> </span><span class="n">score</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">FROM</span><span class="w"> </span><span class="n">best_per_page</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">WHERE</span><span class="w"> </span><span class="n">score</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="mi">0</span><span class="p">.</span><span class="mi">52</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">ORDER</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="n">score</span><span class="w"> </span><span class="k">DESC</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">LIMIT</span><span class="w"> </span><span class="mi">20</span><span class="p">;</span></span></span></code></pre>
</div>
</div>
</div>
<h3 id="filtering-by-content-type">Filtering by content type<a class="anchor-link" id="filtering-by-content-type"></a></h3>
<p>The site has blog, event, talk, and contributor, in the widget and on <code>/search/</code>, you can search for <strong>all at once</strong> or a single type. In the API, this is the <code>content_type</code> field in <code>POST /search</code>; in SQL, <code>AND p.content_type = %s</code> is added when a single type is selected.</p>
<h3 id="sort-order-in-the-widget">Sort order in the widget<a class="anchor-link" id="sort-order-in-the-widget"></a></h3>
<p>In SQL, results are ranked by similarity (<code>ORDER BY score DESC</code>), &ldquo;what matches the query best?&rdquo;</p>
<p>On a community site, <strong>recent material often matters as much as the top semantic match</strong>. An older article might score 0.71 while a newer post on the same topic scores 0.66. I still build the shortlist in SQL (one best chunk per document, <code>min_score</code> threshold), but the API then <strong>re-sorts blog, event, and talk by publication date</strong>, newest first. Contributors and rows without a date stay at the bottom.</p>
<p>The widget still shows the <strong>similarity score</strong> on each card so you can see why the page was included:</p>
<p><figure>
<img decoding="async" src="https://percona.community/blog/2026/05/search-part-2-postgres-widget-scores.png" alt="Widget search results with similarity scores"></figure>
</p>
<h2 id="summary">Summary<a class="anchor-link" id="summary"></a></h2>
<p><strong>Postgres layer</strong>: I set this up without a separate vector DB, using pgvector in Percona, two table modifications for chunking, auxiliary tables for background indexing, HNSW, and SQL with &ldquo;best-fit chunk per document.&rdquo; The indexer processes RSS and HTML; I manage the database in pgAdmin.</p>
<p>Currently, the search index has about <strong>803</strong> documents and <strong>1,656</strong> vectors, thousands of rows, not billions. This is a community-scale setup: a single Postgres instance on EC2, embedding on the CPU, HNSW on all chunks, the solutions above were chosen with this in mind. When I add videos, GitHub issues, and the forum, the volume will grow, then I&rsquo;ll re-evaluate the indexing time and hardware.</p>
<h3 id="note-from-the-author">Note from the author<a class="anchor-link" id="note-from-the-author"></a></h3>
<p>About <strong>six months ago</strong>, I already tried to set up something similar to Postgres + vectors using AI agents. Back then, I kept running into the same issues: a clunky <strong>startup</strong> of the environment, the <strong>schema</strong> and its <strong>modifications</strong>, <strong>initializing Percona Distribution for PostgreSQL</strong>, and pgvector, the agent would either skip a step or suggest incompatible configuration snippets.</p>
<p>This time, with <a href="https://percona.community" target="_blank" rel="noopener noreferrer">percona.community</a>, went better: the agent set up Compose, <code>ensure_*</code>, search SQL, and the admin dashboard, without that series of failures at startup. More time was spent on the logic (chunks, <code>min_score</code>, result ordering) rather than on &ldquo;why the database won&rsquo;t start.&rdquo;</p>
<p>If you try this setup yourself or notice any inaccuracies, please leave a comment.</p>

<p>The post <a rel="nofollow" href="https://percona.community/blog/2026/05/31/semantic-search-on-postgresql-part-2/">Building Smart Semantic Search using PostgreSQL and pgvector. Case Study &#8211; Part 2 &#8211; Postgres Layer</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>MariaDB Server 12.3 LTS Released</title>
      <link>https://mariadb.org/mariadb-server-12-3-lts-released/</link>
      <pubDate>Fri, 29 May 2026 16:47:25 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.org/">MariaDB.org</source>
      <description><![CDATA[<p>The MariaDB Foundation is pleased to announce the availability of MariaDB Server 12.3 LTS, the latest Long Term Support release of MariaDB Server. The first GA of the 12.3 series is 12.3.2. …<br />
Continue reading \"MariaDB Server 12.3 LTS Released\"<br />
The post MariaDB Server 12.3 LTS Released appeared first on MariaDB.org.</p>
<p>The post <a rel="nofollow" href="https://mariadb.org/mariadb-server-12-3-lts-released/">MariaDB Server 12.3 LTS Released</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>The MariaDB Foundation is pleased to announce the availability of MariaDB Server 12.3 LTS, the latest Long Term Support release of MariaDB Server. The first GA of the 12.3 series is 12.3.2. &hellip; </p>
<p class="link-more"><a href="https://mariadb.org/mariadb-server-12-3-lts-released/" class="more-link">Continue reading<span class="screen-reader-text"> &ldquo;MariaDB Server 12.3 LTS Released&rdquo;</span></a></p>
<p>The post <a rel="nofollow" href="https://mariadb.org/mariadb-server-12-3-lts-released/">MariaDB Server 12.3 LTS Released</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>

<p>The post <a rel="nofollow" href="https://mariadb.org/mariadb-server-12-3-lts-released/">MariaDB Server 12.3 LTS Released</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Building Smart Semantic Search using PostgreSQL and pgvector. Case Study &#8211; Part 1</title>
      <link>https://percona.community/blog/2026/05/29/semantic-search-on-postgresql-part-1/</link>
      <pubDate>Fri, 29 May 2026 11:00:00 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://percona.community/blog/">Percona Community Blog - learn about MySQL, MariaDB, PostgreSQL, and MongoDB</source>
      <description><![CDATA[<p>Type “zero downtime database migration” into the site’s search bar and you’ll get articles and talks about database migration with minimal downtime, even if those words aren’t in the titles or content. This is semantic search on PostgreSQL and pgvector, without paid embedding APIs or a separate vector database. In this series I’ll cover how it works and why I chose this stack.</p>
<p>The post <a rel="nofollow" href="https://percona.community/blog/2026/05/29/semantic-search-on-postgresql-part-1/">Building Smart Semantic Search using PostgreSQL and pgvector. Case Study &#8211; Part 1</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>Type &ldquo;zero downtime database migration&rdquo; into the site&rsquo;s search bar and you&rsquo;ll get articles and talks about database migration with minimal downtime, even if those words aren&rsquo;t in the titles or content. This is <strong>semantic search</strong> on <strong>PostgreSQL</strong> and <strong><a href="https://github.com/pgvector/pgvector" target="_blank" rel="noopener noreferrer">pgvector</a></strong>, without paid embedding APIs or a separate vector database. In this series I&rsquo;ll cover how it works and why I chose this stack.</p>
<p>I&rsquo;ll walk through how and why I built the search for our community site: blog, events, talks, and profiles. The post should help if you want to repeat the approach or need a practical case study on simple components. If you&rsquo;ve done something similar, I&rsquo;d like to hear your feedback.</p>
<p><figure>
<img decoding="async" src="https://percona.community/blog/2026/05/search-part-1-intro-kubernetes.png" alt="Smart Semantic Search using PostgreSQL and pgvector - Introduction"></figure>
</p>
<h2 id="context-website-search-and-task">Context: Website, Search, and Task<a class="anchor-link" id="context-website-search-and-task"></a></h2>
<p>The community team has a website on <strong>Hugo</strong>, an open source static site generator, hosted for free on <strong>GitHub Pages</strong>. The site has articles, events, talks, videos, and more.</p>
<blockquote>
<p>If you&rsquo;re thinking of starting your own, I recommend checking out these examples: <a href="https://blog.koehntopp.info/" target="_blank" rel="noopener noreferrer">blog.koehntopp.info</a>, <a href="https://openeverest.io/" target="_blank" rel="noopener noreferrer">openeverest.io</a>, <a href="https://perconalive.com/" target="_blank" rel="noopener noreferrer">perconalive.com</a>, <a href="https://oursqlfoundation.org/" target="_blank" rel="noopener noreferrer">oursqlfoundation.org</a></p>
</blockquote>
<p>But a Hugo site is a collection of HTML files without a backend. Search or filters only work via frontend JS or an external service. For a long time our site had no search at all. Then <strong>Kai Wagner</strong> contributed a JS search for the blog that matched exact words (<a href="https://percona.community/blog" target="_blank" rel="noopener noreferrer">percona.community/blog</a>).</p>
<p>Recently our community lead <strong>Laura Czajkowski</strong> asked for smart AI search on the site. We tried several off-the-shelf products; they were either too expensive or a poor fit. We also want search to cover more than the site itself eventually: videos from other platforms, the forum, our GitHub repos, and maybe documentation later.</p>
<p>I suggested building it ourselves. Modern AI assistants are good enough for a prototype like this. Below I&rsquo;ll explain the stack.</p>
<h2 id="what-well-do">What We&rsquo;ll Do<a class="anchor-link" id="what-well-do"></a></h2>
<p>The site stays on Hugo and GitHub Pages. The search service runs <strong>separately</strong>; for this architecture that&rsquo;s the sensible option. The goal is simple: the user types a query in plain language and gets a list of semantically relevant links.</p>
<p>Kai&rsquo;s keyword search was a step forward, but it doesn&rsquo;t catch <strong>meaning</strong>. Type &ldquo;postgresql&rdquo; and you get pages where the word appears. An article about slow queries or replication may be missing if the wording is different. <strong>Semantic search</strong> works differently: the query and documents become <strong>vectors</strong>, numeric representations of meaning (<strong>embedding</strong>). Similar meaning lands nearby in vector space even when the words differ. A query like &ldquo;how to speed up slow queries in MySQL&rdquo; can surface tuning and optimization content without those words in the title.</p>
<p>Why not another engine? <strong><a href="https://opensearch.org/" target="_blank" rel="noopener noreferrer">OpenSearch</a></strong> is a solid open-source option: full-text and vector search, mature ecosystem. I also looked at <strong><a href="https://manticoresearch.com/" target="_blank" rel="noopener noreferrer">Manticore Search</a></strong>. Both work, but <strong>semantics</strong> still need an embedding pipeline (model at index time and on each query). That&rsquo;s another service to run beside the model.</p>
<p>I wanted my own stack on <strong>Postgres</strong> with pgvector: a practical experiment, not a hunt for the perfect search product. <strong>PostgreSQL with <a href="https://github.com/pgvector/pgvector" target="_blank" rel="noopener noreferrer">pgvector</a></strong> keeps page metadata, chunks, vectors, and query history in one database. <strong><a href="https://docs.percona.com/postgresql/18/index.html" target="_blank" rel="noopener noreferrer">Percona Distribution for PostgreSQL 18</a></strong> ships pgvector in the distribution; run <code>CREATE EXTENSION vector</code> and you&rsquo;re set.</p>
<p>The plan has four parts:</p>
<ol>
<li><strong>Widget</strong> on the site: search field and results (plain JS; Hugo unchanged).</li>
<li><strong>API</strong>: takes the query, embeds it with the same model as indexing, searches the DB, returns JSON links.</li>
<li><strong>Indexer</strong>: background worker that reads RSS/HTML, chunks text, embeds, writes to the DB.</li>
<li><strong>PostgreSQL + pgvector</strong>: one database for metadata, chunks, vectors, and search history.</li>
</ol>
<p>Hugo stays static; the smart parts live in a separate service. No separate vector DB, no paid embedding API, no RAG chat, only links.</p>
<p>The diagram shows two flows: <strong>search</strong> (user query) and <strong>indexing</strong> (refresh the DB on demand or on a schedule). Top to bottom, from the user:</p>
<pre class="mermaid">
flowchart TB
User(["&#128100; User"])
Widget["&#128269; JS widget<br>percona.community &middot; GitHub Pages"]
API["&#9889; FastAPI<br>search.percona.community"]
Model["&#129504; Embedding model<br>shared &middot; API &amp; indexer"]
DB[("&#128452;&#65039; PostgreSQL + pgvector")]
Content["&#128240; Content<br>blog &middot; events &middot; talks"]
Indexer["&#128229; Indexer worker"]
User --&gt;|"&#9312; query"| Widget
Widget --&gt;|"&#9313; POST /search"| API
API |embed query| Model
API |"&#9314; vector search"| DB
API --&gt;|"&#9315; results"| Widget
Widget --&gt; User
Content --&gt;|"A. RSS + HTML"| Indexer
Indexer |embed chunks| Model
Indexer --&gt;|"B. chunks + vectors"| DB
style User fill:#e1f5ff
style Widget fill:#fff4e6
style Content fill:#fff9e6
style API fill:#ffe6e6
style Model fill:#fff0f5
style Indexer fill:#f0e6ff
style DB fill:#e6ffe6
</pre>
<p>The diagram shows the shared <strong>embedding model</strong>; worth stating explicitly anyway. <strong>The indexer and the API must use the same model.</strong> Query vectors and stored vectors must share one space or search is meaningless. Don&rsquo;t mix Nomic at index time with OpenAI at query time, for example. The widget only sends text; it doesn&rsquo;t know which model runs behind the API.</p>
<p>On paper it looked simple. In practice I changed the database schema <strong>three times</strong> and tuned ranking so blog posts didn&rsquo;t crowd out events and talks. The <strong>similarity threshold</strong> mattered more than I expected: one parameter, large swing in results. Still, within a few days we had a working beta on the live site. Here&rsquo;s what shipped.</p>
<h2 id="the-result-spoiler">The Result (Spoiler)<a class="anchor-link" id="the-result-spoiler"></a></h2>
<p>It took about <strong>three unhurried days</strong> and roughly <strong>$20 in Cursor tokens</strong> to build, debug, and deploy. Try it on <strong><a href="https://percona.community" target="_blank" rel="noopener noreferrer">percona.community</a></strong> (search icon in the header) or <strong><a href="https://percona.community/search/" target="_blank" rel="noopener noreferrer">percona.community/search/</a></strong>.</p>
<p>The index currently covers the site: blog, events, talks, member profiles. Video from other platforms, the forum, and GitHub are planned; the design should allow new sources without replacing the stack.</p>
<p>This is <strong>beta</strong>: the content is public and search isn&rsquo;t business-critical, but I watch stability and security.</p>
<h3 id="website-widget">Website Widget<a class="anchor-link" id="website-widget"></a></h3>
<p>The header has a search icon. Click it to get an input field and a popup with results, <strong>similarity score</strong> (0 to 1, how close the hit is in meaning), and API latency. The site stays static; the widget calls <code>search.percona.community</code> and renders JSON. &ldquo;All results&rdquo; opens <code>/search/</code>.</p>
<p>Try it on <a href="https://percona.community" target="_blank" rel="noopener noreferrer">percona.community</a>, e.g. <code>slow queries mysql tuning</code> or <code>kubernetes operator database</code>. Comments welcome if something feels off.</p>
<p><figure>
<img decoding="async" src="https://percona.community/blog/2026/05/search-part-1-intro-pz-talks.png" alt="Smart Semantic Search using PostgreSQL and pgvector - Widget"></figure>
</p>
<h3 id="full-results-page">Full Results Page<a class="anchor-link" id="full-results-page"></a></h3>
<p>A separate <code>/search/</code> page with filters by content type, cards, and links.</p>
<p><figure>
<img decoding="async" src="https://percona.community/blog/2026/05/search-part-1-intro-page.png" alt="Smart Semantic Search using PostgreSQL and pgvector - Search Page"></figure>
</p>
<p><a href="https://percona.community/search/?q=Postgres+backup+solutions&amp;type=blog" target="_blank" rel="noopener noreferrer">Example</a></p>
<h3 id="api">API<a class="anchor-link" id="api"></a></h3>
<p><strong>FastAPI</strong> at <code>https://search.percona.community</code>: embed the query, search Postgres, return JSON with links, scores, and timings (model vs database).</p>
<p>The service runs on <strong>AWS EC2</strong> in Docker Compose: API, indexer, Postgres.</p>
<h3 id="demo-dashboard">Demo Dashboard<a class="anchor-link" id="demo-dashboard"></a></h3>
<p>The Cursor AI agent handled a lot of the boilerplate, so I also built a <strong>dev dashboard</strong> (<code>/demo</code>) to test search, run indexing, inspect history, and browse indexed chunks. Not for production, but it saved debugging time.</p>
<p>Demo Dashboard</p>
<figure>
<img decoding="async" src="https://percona.community/blog/2026/05/search-part-1-intro-demo-search.png" alt="Smart Semantic Search using PostgreSQL and pgvector - Demo Dashboard Search"></figure>

<p>Search history: making search better</p>
<p><figure>
<img decoding="async" src="https://percona.community/blog/2026/05/search-part-1-intro-demo-history.png" alt="Smart Semantic Search using PostgreSQL and pgvector - Demo Dashboard Search history"></figure>
</p>
<p>Indexing status, to see when search data was last updated</p>
<p><figure>
<img decoding="async" src="https://percona.community/blog/2026/05/search-part-1-intro-demo-status.png" alt="Smart Semantic Search using PostgreSQL and pgvector - Demo Dashboard Indexing status"></figure>
</p>
<p>Indexed documents with the ability to view data and chunks.</p>
<p><figure>
<img decoding="async" src="https://percona.community/blog/2026/05/search-part-1-intro-demo-pages.png" alt="Smart Semantic Search using PostgreSQL and pgvector - Demo Dashboard Indexed documents"></figure>
</p>
<h3 id="what-i-used">What I Used<a class="anchor-link" id="what-i-used"></a></h3>
<p>Briefly, <strong>why</strong> this stack (deeper comparison in <strong>part two</strong>):</p>
<ul>
<li>
<p><strong><a href="https://www.postgresql.org/" target="_blank" rel="noopener noreferrer">PostgreSQL</a></strong> + <strong><a href="https://github.com/pgvector/pgvector" target="_blank" rel="noopener noreferrer">pgvector</a></strong>: vectors and metadata in one DB. Cosine similarity plus an HNSW index is enough at community scale. (<a href="https://docs.percona.com/postgresql/18/enable-extensions.html#pgvector" target="_blank" rel="noopener noreferrer">pgvector in Percona docs</a>)</p>
</li>
<li>
<p><strong><a href="https://docs.percona.com/postgresql/18/index.html" target="_blank" rel="noopener noreferrer">Percona Distribution for PostgreSQL 18</a></strong>: PostgreSQL with pgvector and a Docker image. Vanilla Postgres works too if you install the extension; I used Percona to try &ldquo;their&rdquo; Postgres + pgvector in a real deploy.</p>
</li>
<li>
<p><strong><a href="https://www.python.org/" target="_blank" rel="noopener noreferrer">Python</a></strong> + <strong><a href="https://fastapi.tiangolo.com/" target="_blank" rel="noopener noreferrer">FastAPI</a></strong>: fast API setup, OpenAPI included, good libraries for crawl/embed/Postgres.</p>
</li>
<li>
<p><strong><a href="https://huggingface.co/nomic-ai/nomic-embed-text-v1" target="_blank" rel="noopener noreferrer">nomic-embed-text-v1</a></strong> + <strong><a href="https://www.sbert.net/" target="_blank" rel="noopener noreferrer">sentence-transformers</a></strong>: open model, 768 dims, CPU-friendly, no per-chunk API bill. Index and query must use the <strong>same</strong> model; Nomic fits. I&rsquo;ll compare others later.</p>
</li>
<li>
<p><strong><a href="https://gohugo.io/" target="_blank" rel="noopener noreferrer">Hugo</a></strong> + <strong>JavaScript</strong>: thin widget on existing static site.</p>
</li>
<li>
<p><strong><a href="https://www.docker.com/" target="_blank" rel="noopener noreferrer">Docker</a></strong> / <strong>Docker Compose</strong>: same layout locally and on EC2.</p>
</li>
<li>
<p><strong><a href="https://aws.amazon.com/ec2/" target="_blank" rel="noopener noreferrer">AWS EC2</a></strong> + <strong>nginx</strong>: HTTPS on <code>search.percona.community</code>, CORS for GitHub Pages.</p>
</li>
<li>
<p><strong><a href="https://cursor.com/" target="_blank" rel="noopener noreferrer">Cursor</a></strong>: main dev tool; its AI agent helped with boilerplate, wiring API to the demo, and Docker fixes. I still reviewed everything. Without it, the same work would have taken weeks.</p>
</li>
</ul>
<h3 id="how-long-it-took">How long it took<a class="anchor-link" id="how-long-it-took"></a></h3>
<ul>
<li><strong>~6 hours</strong> with Cursor to a first prototype: crawl, API, Docker, basic demo;</li>
<li><strong>~2 more days</strong> for schema changes, per-type ranking, embed/page widget, search history, dashboard, indexer fixes, EC2 deploy;</li>
<li><strong>~$20</strong> in Cursor tokens total.</li>
</ul>
<p>Without AI I&rsquo;d have stretched the same work over weeks. With the agent I mostly wrote tasks, checked output, and fixed edges.</p>
<h3 id="about-the-code-and-repository">About the code and repository<a class="anchor-link" id="about-the-code-and-repository"></a></h3>
<p>I&rsquo;m not publishing the repo yet. The code is tied to <strong>percona.community</strong>: our RSS feeds, content types, Hugo widget, EC2 layout. It&rsquo;s an internal prototype, not a reusable library.</p>
<p>If you wanted a drop-in repo: porting someone else&rsquo;s monolith often takes longer than rebuilding from a clear sketch. Part two will have architecture, schema, and stack notes enough for a Cursor agent (or similar) to rebuild for <strong>your</strong> feeds and UI.</p>
<p>Interested in a <strong>generic open source</strong> or <strong>search-as-a-service</strong> version? Say so in the comments; I&rsquo;m weighing whether it&rsquo;s worth a separate project.</p>
<h3 id="whats-next">What&rsquo;s Next<a class="anchor-link" id="whats-next"></a></h3>
<p>Try search on <a href="https://percona.community" target="_blank" rel="noopener noreferrer">percona.community</a> and comment what you find, especially where semantics beat the old substring search.</p>
<p>Part <strong>two</strong> will go inside: schema (including those three rewrites), chunking, HNSW, per-type result caps, and a local Docker Compose walkthrough.</p>

<p>The post <a rel="nofollow" href="https://percona.community/blog/2026/05/29/semantic-search-on-postgresql-part-1/">Building Smart Semantic Search using PostgreSQL and pgvector. Case Study &#8211; Part 1</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>MariaDB Community Server 12.3 LTS: How It Scales AI Workloads and Delivers 4x Write Performance</title>
      <link>https://mariadb.com/resources/blog/mariadb-community-server-12-3-lts-how-it-scales-ai-workloads-and-delivers-4x-write-performance/</link>
      <pubDate>Thu, 28 May 2026 19:27:14 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.com/">MariaDB</source>
      <description><![CDATA[<p>We are thrilled to announce that MariaDB Community Server 12.3 has reached Generally Available (GA) status. As our latest Long […]</p>
<p>The post <a rel="nofollow" href="https://mariadb.com/resources/blog/mariadb-community-server-12-3-lts-how-it-scales-ai-workloads-and-delivers-4x-write-performance/">MariaDB Community Server 12.3 LTS: How It Scales AI Workloads and Delivers 4x Write Performance</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>We are thrilled to announce that MariaDB Community Server 12.3 has reached Generally Available (GA) status. As our latest Long Term Maintenance (LTS) release, version 12.3 marks the culmination of the 12.x rolling release cycle (12.0&ndash;12.2), bringing together a year of rapid innovation into a rock-solid, production-ready package maintained for the next three years. From scaling modern AI&hellip;</p>
<p><a href="https://mariadb.com/resources/blog/mariadb-community-server-12-3-lts-how-it-scales-ai-workloads-and-delivers-4x-write-performance/" rel="nofollow">Source</a></p>

<p>The post <a rel="nofollow" href="https://mariadb.com/resources/blog/mariadb-community-server-12-3-lts-how-it-scales-ai-workloads-and-delivers-4x-write-performance/">MariaDB Community Server 12.3 LTS: How It Scales AI Workloads and Delivers 4x Write Performance</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Percona Operator for PostgreSQL 3.0.0: Hard Fork, OLM Scoping, Major Upgrades</title>
      <link>https://www.percona.com/blog/percona-operator-for-postgresql-3-0-0-hard-fork-olm-scoping-major-upgrades/</link>
      <pubDate>Thu, 28 May 2026 13:29:03 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://www.percona.com/blog/">Blog - Percona</source>
      <description><![CDATA[<p>The Percona Operator for PostgreSQL 3.0.0 is here. This is the release that completes the hard fork of the operator from the Crunchy Data PostgreSQL Operator into a fully independent project, with a dedicated upstream.pgv2.percona.com API group for the inherited CRDs, an automatic CRD-rename rollout for existing 2.x installs on upgrade, and a public roadmap … Continued<br />
The post Percona Operator for PostgreSQL 3.0.0: Hard Fork, OLM Scoping, Major Upgrades appeared first on Percona.</p>
<p>The post <a rel="nofollow" href="https://www.percona.com/blog/percona-operator-for-postgresql-3-0-0-hard-fork-olm-scoping-major-upgrades/">Percona Operator for PostgreSQL 3.0.0: Hard Fork, OLM Scoping, Major Upgrades</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p><img decoding="async" loading="lazy" class="aligncenter wp-image-47941 size-large" src="https://www.percona.com/wp-content/uploads/2026/05/hero-4-1024x375.png" alt="" width="1024" height="375"></p>
<p><span style="font-weight: 400"><br>
The <a href="https://github.com/percona/percona-postgresql-operator/tree/v3.0.0">Percona Operator for PostgreSQL 3.0.0</a> is here. This is the release that completes the hard fork of the operator from the Crunchy Data PostgreSQL Operator into a fully independent project, with a dedicated <em>upstream.pgv2.percona.com</em> API group for the inherited CRDs, an automatic CRD-rename rollout for existing 2.x installs on upgrade, and a <a href="https://github.com/orgs/percona/projects/10/views/6">public roadmap</a> that drives what comes next.<br>
</span><span style="font-weight: 400"><br>
This release ships three headline changes that matter for production teams. The <strong>CRD renaming under a Percona-owned API group</strong>, which finally lets the Crunchy operator and the Percona operator coexist in the same Kubernetes cluster. <strong>Proper OLM namespace scoping</strong>&nbsp;for OpenShift installations. And the <strong>move to the official Percona Distribution image for major PostgreSQL version upgrades</strong>, aligning the upgrade path with the same binaries that run in your clusters.</span></p>
<p>&nbsp;</p>
<p><span style="font-weight: 400">All three land in service of the same goal: making 3.0.0 a clean, durable operational baseline for the operator&rsquo;s next several years as an independent project. Future releases will be shaped by what the community asks for and contributes back. The public roadmap is the durable signal of that commitment.</span></p>
<p><span style="font-weight: 400">In this post, you will learn about:</span></p>
<ul>
<li style="font-weight: 400"><span style="font-weight: 400">The hard fork and how the CRD rename unlocks coexistence with the Crunchy operator</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">OLM namespace-scoping improvements for OpenShift installations</span></li>
<li style="font-weight: 400">The move to the official Percona Distribution image for major PostgreSQL version upgrades</li>
<li style="font-weight: 400"><span style="font-weight: 400">Other improvements and the <strong>2.7.0</strong> deprecation</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Supported PostgreSQL versions and platforms</span></li>
</ul>
<p>&nbsp;</p>
<h2><b>Hard fork: CRDs renamed under </b><em><b>upstream.pgv2.percona.com</b></em><a class="anchor-link" id="hard-fork-crds-renamed-under-upstream-pgv2-percona-com"></a></h2>
<p><img decoding="async" loading="lazy" class="aligncenter wp-image-47942 size-large" src="https://www.percona.com/wp-content/uploads/2026/05/crd-rename-1024x393.png" alt="" width="1024" height="393"></p>
<p><span style="font-weight: 400">The Percona Operator for PostgreSQL has, until now, been a soft fork. Custom Resources inherited from Crunchy PGO used the upstream </span><em><span style="font-weight: 400">postgres-operator.crunchydata.com</span></em><span style="font-weight: 400"> API group. The two operators shared CRDs, which meant you could only run one of them in a given Kubernetes cluster. Installing both would lead to overlapping CRDs, conflicting webhooks, and finalizer collisions, so platform teams had to pick a side before they had finished evaluating.</span></p>
<p><span style="font-weight: 400">Starting with <strong>3.0.0</strong>, every inherited CRD is renamed into a new dedicated </span><em><span style="font-weight: 400">upstream.pgv2.percona.com</span></em><span style="font-weight: 400"> API group (</span><a href="https://perconadev.atlassian.net/browse/K8SPG-1007"><span style="font-weight: 400">K8SPG-1007</span></a><span style="font-weight: 400">). Percona&rsquo;s own native CRDs (such as </span><span style="font-weight: 400">PerconaPGCluster</span><span style="font-weight: 400"> under </span><em><span style="font-weight: 400">pgv2.percona.com/v2</span></em><span style="font-weight: 400">) are unchanged. The change applies to the inherited resources: </span><span style="font-weight: 400">PostgresCluster</span><span style="font-weight: 400">, </span><span style="font-weight: 400">PGUpgrade</span><span style="font-weight: 400">, </span><span style="font-weight: 400">PGAdmin</span><span style="font-weight: 400">, and the rest.</span></p>
<p>&nbsp;</p>
<h3><strong>Coexistence: running both operators in the same cluster</strong><a class="anchor-link" id="coexistence-running-both-operators-in-the-same-cluster"></a></h3>
<p><span style="font-weight: 400">The practical effect is that t</span><b>he Crunchy Data PostgreSQL Operator and the Percona Operator for PostgreSQL can now run on the same Kubernetes cluster at the same time</b><span style="font-weight: 400">, even in the <strong>same</strong> namespaces, with no CRD or webhook conflict. That unlocks a few real workflows: evaluating both operators on the same staging cluster without spinning up a second cluster, running existing Crunchy-managed clusters in some namespaces while bringing up new Percona-managed clusters in others, or testing a new database version on the Percona side while production stays on Crunchy until you are confident. The choice between the two operators stops being all-or-nothing.</span></p>
<p>&nbsp;</p>
<h3><strong>Upgrade behavior for existing 2.x installs</strong><a class="anchor-link" id="upgrade-behavior-for-existing-2-x-installs"></a></h3>
<p><span style="font-weight: 400">For an existing install, the upgrade to <strong>3.0.0</strong> is mechanically simple. The operator creates the new-API-group CRDs alongside the legacy ones, then runs a one-time migration that updates dependent objects (Secrets, certificates, finalizer references) to point at the new CRD instances. Existing custom resources keep working through the legacy CRDs during the transition, and once migration completes, all reconciliation moves to the new group.</span></p>
<p><b>Old <em>PostgresCluster</em> reference:<br>
</b></p>
<pre class="urvanov-syntax-highlighter-plain-tag">apiVersion: postgres-operator.crunchydata.com/v1beta1
kind: PostgresCluster
metadata:
  name: cluster1</pre>
<p><b><br>
New (after upgrade to 3.0.0):</b></p>
<pre class="urvanov-syntax-highlighter-plain-tag">apiVersion: upstream.pgv2.percona.com/v1beta1
kind: PostgresCluster
metadata:
  name: cluster1</pre>
<p>&nbsp;</p>
<p><span style="font-weight: 400">Day-to-day, your </span><em><span style="font-weight: 400">PerconaPGCluster</span></em><span style="font-weight: 400"> Custom Resource (the one most teams interact with directly) is unchanged. The rename mostly matters in three situations: when a kubectl filter or a GitOps repository hard-codes the old API group, when a CI pipeline references the legacy CRD by name, and when you run the Percona and Crunchy operators side by side and need them not to collide.</span></p>
<p><span style="font-weight: 400">Note: During the CRD migration on upgrade, the release notes report brief disruptions to pgBackRest operations (typically 1 to 2 minutes) while Kubernetes propagates certificate changes. Plan the upgrade during a maintenance window if backup continuity is critical, or pause scheduled backups during the upgrade.</span></p>
<p><span style="font-weight: 400">Full details on the API-group change are in the </span><a href="https://docs.percona.com/percona-operator-for-postgresql/latest/"><span style="font-weight: 400">Percona PostgreSQL operator documentation</span></a><span style="font-weight: 400">.</span></p>
<p>&nbsp;</p>
<h2><b>Improved OLM namespace scoping for OpenShift</b><a class="anchor-link" id="improved-olm-namespace-scoping-for-openshift"></a></h2>
<p><img decoding="async" loading="lazy" class="aligncenter wp-image-47943 size-large" src="https://www.percona.com/wp-content/uploads/2026/05/olm-scoping-1024x393.png" alt="" width="1024" height="393"></p>
<p><span style="font-weight: 400">OpenShift users install operators through the OpenShift Lifecycle Manager (OLM), and OLM enforces an </span><em><span style="font-weight: 400">OperatorGroup</span></em><span style="font-weight: 400"> to scope which namespaces an operator watches. In practice, 2.x had quirks: teams that selected &ldquo;Single namespace&rdquo; mode would sometimes see the operator reconciling CRs in other namespaces, and teams in &ldquo;All namespaces&rdquo; mode would sometimes see incomplete coverage when CRs were created in newly-added namespaces.</span></p>
<p><span style="font-weight: 400">3.0.0 fixes this by aligning the operator&rsquo;s namespace watch list with the </span><em><span style="font-weight: 400">OperatorGroup</span></em><span style="font-weight: 400"> that OLM applies. All-namespaces installs watch all namespaces. Single-namespace installs respect the </span><span style="font-weight: 400">targetNamespaces</span><span style="font-weight: 400"> set on the </span><em><span style="font-weight: 400">OperatorGroup</span></em><span style="font-weight: 400">.</span></p>
<p>&nbsp;</p>
<h3>Why it matters in shared infrastructure<a class="anchor-link" id="why-it-matters-in-shared-infrastructure"></a></h3>
<p><span style="font-weight: 400">For an OpenShift platform team running shared infrastructure, this distinction matters operationally. A typical setup has the database operator installed once in a platform namespace (such as </span><span style="font-weight: 400">openshift-operators</span><span style="font-weight: 400">) but expected to serve </span><span style="font-weight: 400">PerconaPGCluster</span><span style="font-weight: 400"> resources owned by individual application teams in their own namespaces. If the operator over-reaches into namespaces it should not watch, RBAC noise multiplies. If it under-reaches, application teams file tickets about clusters that never reconcile. The 3.0.0 alignment with </span><em><span style="font-weight: 400">OperatorGroup</span></em><span style="font-weight: 400"> semantics removes both failure modes.</span></p>
<p>&nbsp;</p>
<h3>OperatorGroup wiring<a class="anchor-link" id="operatorgroup-wiring"></a></h3>
<p><span style="font-weight: 400">For users installing through OLM via the OpenShift web console, the install flow is unchanged. The fix is in how the operator&rsquo;s reconciler interprets the OLM-supplied namespace scope after install. For users who manage <em>OperatorGroups</em> directly, a single-namespace install looks like this:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">apiVersion: operators.coreos.com/v1
kind: OperatorGroup
metadata:
  name: percona-pg-operator-group
  namespace: postgres-prod
spec:
  targetNamespaces:
    - postgres-prod</pre>
<p>And an all-namespaces install:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">apiVersion: operators.coreos.com/v1
kind: OperatorGroup
metadata:
  name: percona-pg-operator-group
  namespace: openshift-operators
spec: {}</pre>
<p><span style="font-weight: 400">The empty </span><span style="font-weight: 400">spec: {}</span><span style="font-weight: 400"> (or an </span><span style="font-weight: 400">OperatorGroup</span><span style="font-weight: 400"> with no </span><span style="font-weight: 400">targetNamespaces</span><span style="font-weight: 400">) means &ldquo;watch all namespaces&rdquo; by OLM convention. The 3.0.0 operator now honors that.</span></p>
<p>&nbsp;</p>
<p><b><i>Note:</i></b><i><span style="font-weight: 400"> After you upgrade an existing 2.x install to 3.0.0, the operator may begin reconciling </span></i><i><span style="font-weight: 400">PerconaPGCluster</span></i><i><span style="font-weight: 400"> resources in namespaces it had previously ignored due to the prior scoping bug. Audit existing CRs across your cluster before upgrading, especially if you have stale test clusters in unintended namespaces. The release notes call this out explicitly.</span></i></p>
<p><b><i>Note for community vs certified bundle users: </i></b><i><span style="font-weight: 400">Community OLM bundles did not support cluster-wide (all-namespaces) mode in earlier versions, 3.0.0 adds it. Certified bundles already supported cluster-wide mode, but they used a separate </span></i><i><span style="font-weight: 400">stable-cw</span></i><i><span style="font-weight: 400"> channel for it with 3.0.0 the channels are unified, so users upgrading from a certified </span></i><i><span style="font-weight: 400">stable-cw</span></i><i><span style="font-weight: 400"> install need to switch their subscription channel to </span></i><i><span style="font-weight: 400">stable</span></i><i><span style="font-weight: 400"> to receive the upgrade.</span></i></p>
<p><span style="font-weight: 400">For the full install workflow on OpenShift, see the </span><a href="https://docs.percona.com/percona-operator-for-postgresql/latest/openshift.html"><span style="font-weight: 400">OpenShift installation documentation</span></a><span style="font-weight: 400">.</span></p>
<h2><span style="font-weight: 400"><b><br>
Major PostgreSQL version upgrades now use the official Percona Distribution image</b></span><a class="anchor-link" id="major-postgresql-version-upgrades-now-use-the-official-percona-distribution-image"></a></h2>
<p><img decoding="async" loading="lazy" class="aligncenter wp-image-47944 size-large" src="https://www.percona.com/wp-content/uploads/2026/05/major-upgrade-1024x393.png" alt="" width="1024" height="393"><br>
<span style="font-weight: 400">Major-version upgrades (for example, PostgreSQL 17 to 18) require running </span><span style="font-weight: 400">pg_upgrade</span><span style="font-weight: 400">, which needs binaries for both the source and target versions in the same environment. The operator has supported major-version upgrades since 2.x, but it shipped its own dedicated upgrade image to do so. That worked, but it meant a Percona-specific image lived in the upgrade path, separate from the same Percona Distribution for PostgreSQL build that runs in your clusters.</span></p>
<p>&nbsp;</p>
<h3>Switching to the official Percona Distribution image<a class="anchor-link" id="switching-to-the-official-percona-distribution-image"></a></h3>
<p><span style="font-weight: 400">In 3.0.0, the operator switches to using the </span><b>official Percona Distribution for PostgreSQL image</b><span style="font-weight: 400"> for major-version upgrades: </span><em><span style="font-weight: 400">percona/percona-distribution-postgresql-upgrade</span></em><span style="font-weight: 400"> (current tag: </span><em><span style="font-weight: 400">18.4-17.10-16.14-15.18-14.23-1</span></em><span style="font-weight: 400">, which encodes the bundled major versions). The benefit is alignment: the binaries that run </span><span style="font-weight: 400">pg_upgrade</span><span style="font-weight: 400"> are the same binaries that ship in the corresponding </span><span style="font-weight: 400">percona-distribution-postgresql</span><span style="font-weight: 400"> image you already run in production, built from the same source, signed the same way, and patched on the same schedule. The operator orchestrates the upgrade through the </span><span style="font-weight: 400">PerconaPGUpgrade</span><span style="font-weight: 400"> Custom Resource that names the source and target versions, the upgrade image, and the target component images (PostgreSQL, pgBouncer, pgBackRest).</span></p>
<p>&nbsp;</p>
<h3>Running an upgrade through the PerconaPGUpgrade CR<a class="anchor-link" id="running-an-upgrade-through-the-perconapgupgrade-cr"></a></h3>
<p><span style="font-weight: 400">A PostgreSQL 17 to 18 upgrade looks like this:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">apiVersion: pgv2.percona.com/v2
kind: PerconaPGUpgrade
metadata:
  name: cluster1-17-to-18
spec:
  postgresClusterName: cluster1
  image: docker.io/percona/percona-distribution-postgresql-upgrade:18.4-17.10-16.14-15.18-14.23-1
  fromPostgresVersion: 17
  toPostgresVersion: 18
  toPostgresImage: docker.io/percona/percona-distribution-postgresql:18.4-1
  toPgBouncerImage: docker.io/percona/percona-pgbouncer:1.25.2-1
  toPgBackRestImage: docker.io/percona/percona-pgbackrest:2.58.0-2</pre>
<p><span style="font-weight: 400">Apply it with </span><em><span style="font-weight: 400">kubectl apply -f upgrade.yaml -n &lt;namespace&gt;</span></em><span style="font-weight: 400">. The operator reconciles the upgrade as a controlled, observable process: it brings the cluster down for the upgrade window, runs </span><span style="font-weight: 400">pg_upgrade</span><span style="font-weight: 400"> from the bundled image, brings the cluster back up on the target version, and updates pgBouncer and pgBackRest images in the same step.</span></p>
<p><span style="font-weight: 400">Operationally, this matters for teams running on PostgreSQL&rsquo;s annual major-version cadence. Every September brings a new major release; staying on a supported version means executing one major upgrade per cluster per year. Pulling the upgrade image from the same </span><span style="font-weight: 400">percona-distribution-postgresql</span><span style="font-weight: 400"> registry path as the runtime image means image-signature verification, mirror-to-private-registry rules, and CVE-scanning policies you already have in place apply to the upgrade flow without any per-image exception.</span></p>
<p><b><i>Note</i></b><i><span style="font-weight: 400">: The </span></i><i><span style="font-weight: 400">pgaudit</span></i><i><span style="font-weight: 400"> extension is not upgraded automatically. After the operator completes the major version upgrade, drop and recreate </span></i><i><span style="font-weight: 400">pgaudit</span></i><i><span style="font-weight: 400"> manually in each database that uses it: </span></i><i><span style="font-weight: 400">DROP EXTENSION pgaudit;</span></i><i><span style="font-weight: 400"> followed by </span></i><i><span style="font-weight: 400">CREATE EXTENSION pgaudit;</span></i><i><span style="font-weight: 400">. The release notes call this out as a required step (</span></i><a href="https://perconadev.atlassian.net/browse/K8SPG-1022"><i><span style="font-weight: 400">K8SPG-1022</span></i></a><i><span style="font-weight: 400">). Also worth scanning for collation-dependent indexes after the upgrade and refreshing collation metadata with </span></i><i><span style="font-weight: 400">ALTER DATABASE &lt;name&gt; REFRESH COLLATION VERSION;</span></i><i><span style="font-weight: 400"> per the upstream PostgreSQL 18 release notes.</span></i></p>
<p><span style="font-weight: 400">Full procedure, prerequisites, and rollback notes are in the </span><a href="https://docs.percona.com/percona-operator-for-postgresql/latest/update-db-major.html"><span style="font-weight: 400">major version upgrade documentation</span></a><span style="font-weight: 400">.</span></p>
<h2><b>Other Improvements</b><a class="anchor-link" id="other-improvements"></a></h2>
<p><span style="font-weight: 400">Operational polish landed alongside the headline changes:</span></p>
<ul>
<li style="font-weight: 400"><b>Go 1.26 </b><span style="font-weight: 400">update (</span><a href="https://perconadev.atlassian.net/browse/K8SPG-1019"><span style="font-weight: 400">K8SPG-1019</span></a><span style="font-weight: 400">): the operator binary is now built with Go 1.26, picking up performance optimizations, tooling improvements, and the security fixes that landed in the Go runtime since the previous release.</span></li>
<li style="font-weight: 400"><b>pgaudit upgrade documentation </b><span style="font-weight: 400">(</span><a href="https://perconadev.atlassian.net/browse/K8SPG-1022"><span style="font-weight: 400">K8SPG-1022</span></a><span style="font-weight: 400">): the major-version upgrade docs now include an explicit pgaudit drop-and-recreate procedure, surfacing the gotcha that previously caught users mid-upgrade.</span></li>
</ul>
<p><span style="font-weight: 400">The release also defaults the cluster-upgrade documentation to PostgreSQL 18 across all examples and tutorials.</span></p>
<p>&nbsp;</p>
<h3><b>Supported software and platforms</b><a class="anchor-link" id="supported-software-and-platforms"></a></h3>
<p><span style="font-weight: 400">The Percona Operator for PostgreSQL 3.0.0 is developed and tested on:</span></p>
<ul>
<li style="font-weight: 400"><b>PostgreSQL: </b><span style="font-weight: 400">14.23-1, 15.18-1, 16.14-1, 17.10-1, 18.4-1&nbsp;</span></li>
<li style="font-weight: 400"><b>pgBackRest:</b><span style="font-weight: 400"> 2.58.0-2</span></li>
<li style="font-weight: 400"><b>pgBouncer: </b><span style="font-weight: 400">1.25.2-1</span></li>
<li style="font-weight: 400"><b>Patroni:</b><span style="font-weight: 400"> 4.1.3</span></li>
<li style="font-weight: 400"><b>PostGIS:</b><span style="font-weight: 400"> 3.5.6</span></li>
<li style="font-weight: 400"><b>PMM Client:</b> 2.44.1-1 and 3.7.1</li>
</ul>
<p>&nbsp;</p>
<h3><b>Supported Kubernetes platforms:</b><a class="anchor-link" id="supported-kubernetes-platforms"></a></h3>
<ul>
<li style="font-weight: 400"><span style="font-weight: 400">Google Kubernetes Engine (GKE) 1.33 to 1.35</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Amazon Elastic Kubernetes Service (EKS) 1.33 to 1.35</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">OpenShift 4.18 to 4.21</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Azure Kubernetes Service (AKS) 1.33 to 1.35</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Minikube 1.38.1 (Kubernetes v1.35.1) for local development</span></li>
</ul>
<p>&nbsp;</p>
<h3><b>Deprecation: 2.7.0 support dropped</b><a class="anchor-link" id="deprecation-2-7-0-support-dropped"></a></h3>
<p><span style="font-weight: 400">Support for Custom Resource Definitions from operator version 2.7.0 has been removed. If you are still on 2.7.0, upgrade to 2.8.x or 2.9.x first, then upgrade to 3.0.0. The CRD migration described above only handles 2.8.x and 2.9.x to 3.0.0 transitions cleanly.</span></p>
<p>&nbsp;</p>
<h2><b>Conclusion</b><a class="anchor-link" id="conclusion"></a></h2>
<p><span style="font-weight: 400">3.0.0 is the release where the Percona Operator for PostgreSQL becomes a fully independent project. The CRD rename removes the last upstream coupling that mattered operationally. The OLM scoping fix removes a long-standing OpenShift quirk. The official major-version upgrade image removes one of the more painful operational gaps in earlier versions.</span></p>
<p><span style="font-weight: 400">Beyond the technical work, 3.0.0 is also where Percona&rsquo;s commitment to community-driven development moves from intent to mechanism. The </span><a href="https://github.com/orgs/percona/projects/10/views/6"><span style="font-weight: 400">public roadmap</span></a><span style="font-weight: 400"> is open. The </span><a href="https://github.com/percona/percona-postgresql-operator/issues"><span style="font-weight: 400">issue tracker</span></a><span style="font-weight: 400"> is open. The images are freely redistributable. Future releases will be shaped by what the community asks for, files, and contributes back. If there is a feature you want to see in 3.1.0 or 3.2.0, open an issue or a PR, that is where the work happens now.</span></p>
<p>&nbsp;</p>
<h2><b>Try It Out</b><a class="anchor-link" id="try-it-out"></a></h2>
<ul>
<li style="font-weight: 400"><b>Release notes:</b> <a href="https://docs.percona.com/percona-operator-for-postgresql/latest/ReleaseNotes/Kubernetes-Operator-for-PostgreSQL-RN3.0.0.html"><span style="font-weight: 400">Percona Operator for PostgreSQL 3.0.0 Release Notes</span></a></li>
<li style="font-weight: 400"><b>Documentation:</b> <a href="https://docs.percona.com/percona-operator-for-postgresql/latest/"><span style="font-weight: 400">https://docs.percona.com/percona-operator-for-postgresql/latest/</span></a></li>
<li style="font-weight: 400"><b>GitHub:</b> <a href="https://github.com/percona/percona-postgresql-operator"><span style="font-weight: 400">percona/percona-postgresql-operator</span></a></li>
<li style="font-weight: 400"><b>Public roadmap: </b><a href="https://github.com/orgs/percona/projects/10/views/6"><span style="font-weight: 400">https://github.com/orgs/percona/projects/10/views/6</span></a></li>
<li style="font-weight: 400"><b>Issue tracker:</b> <a href="https://github.com/percona/percona-postgresql-operator/issues"><span style="font-weight: 400">https://github.com/percona/percona-postgresql-operator/issues</span></a></li>
<li style="font-weight: 400"><b>Community Forum: </b><a href="https://forums.percona.com/c/postgresql/percona-kubernetes-operator-for-postgresql/68">forums.percona.com</a></li>
</ul>
<p>The post <a href="https://www.percona.com/blog/percona-operator-for-postgresql-3-0-0-hard-fork-olm-scoping-major-upgrades/">Percona Operator for PostgreSQL 3.0.0: Hard Fork, OLM Scoping, Major Upgrades</a> appeared first on <a href="https://www.percona.com">Percona</a>.</p>

<p>The post <a rel="nofollow" href="https://www.percona.com/blog/percona-operator-for-postgresql-3-0-0-hard-fork-olm-scoping-major-upgrades/">Percona Operator for PostgreSQL 3.0.0: Hard Fork, OLM Scoping, Major Upgrades</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>MariaDB Foundation at Oracle’s MySQL Contributor Summit: Ecosystems, Forks and Constructive Coexistence</title>
      <link>https://mariadb.org/mariadb-foundation-at-oracles-mysql-contributor-summit/</link>
      <pubDate>Thu, 28 May 2026 12:33:27 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.org/">MariaDB.org</source>
      <description><![CDATA[<p>Last week, Oracle invited MariaDB Foundation to give a presentation at Oracle’s MySQL Contributor Summit 2026. I had the opportunity to participate remotely and speak about MariaDB’s role within the broader MySQL ecosystem. …<br />
Continue reading \"MariaDB Foundation at Oracle’s MySQL Contributor Summit: Ecosystems, Forks and Constructive Coexistence\"<br />
The post MariaDB Foundation at Oracle’s MySQL Contributor Summit: Ecosystems, Forks and Constructive Coexistence appeared first on MariaDB.org.</p>
<p>The post <a rel="nofollow" href="https://mariadb.org/mariadb-foundation-at-oracles-mysql-contributor-summit/">MariaDB Foundation at Oracle’s MySQL Contributor Summit: Ecosystems, Forks and Constructive Coexistence</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>Last week, Oracle invited MariaDB Foundation to give a presentation at Oracle&rsquo;s MySQL Contributor Summit 2026. I had the opportunity to participate remotely and speak about MariaDB&rsquo;s role within the broader MySQL ecosystem. &hellip; </p>
<p class="link-more"><a href="https://mariadb.org/mariadb-foundation-at-oracles-mysql-contributor-summit/" class="more-link">Continue reading<span class="screen-reader-text"> &ldquo;MariaDB Foundation at Oracle&rsquo;s MySQL Contributor Summit: Ecosystems, Forks and Constructive Coexistence&rdquo;</span></a></p>
<p>The post <a rel="nofollow" href="https://mariadb.org/mariadb-foundation-at-oracles-mysql-contributor-summit/">MariaDB Foundation at Oracle&rsquo;s MySQL Contributor Summit: Ecosystems, Forks and Constructive Coexistence</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>

<p>The post <a rel="nofollow" href="https://mariadb.org/mariadb-foundation-at-oracles-mysql-contributor-summit/">MariaDB Foundation at Oracle’s MySQL Contributor Summit: Ecosystems, Forks and Constructive Coexistence</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>MariaDB Community Server Q2 2026 corrective releases</title>
      <link>https://mariadb.com/resources/blog/mariadb-community-server-q2-2026-corrective-releases/</link>
      <pubDate>Wed, 27 May 2026 19:09:10 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.com/">MariaDB</source>
      <description><![CDATA[<p>MariaDB is pleased to announce the immediate availability of MariaDB Community Server 11.8.8, 11.4.12, 10.11.18, and 10.6.27 corrective releases. See […]</p>
<p>The post <a rel="nofollow" href="https://mariadb.com/resources/blog/mariadb-community-server-q2-2026-corrective-releases/">MariaDB Community Server Q2 2026 corrective releases</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>MariaDB is pleased to announce the immediate availability of MariaDB Community Server 11.8.8, 11.4.12, 10.11.18, and 10.6.27 corrective releases. See the release notes and changelogs for additional details on each release and visit mariadb.com/downloads to download.</p>
<p><a href="https://mariadb.com/resources/blog/mariadb-community-server-q2-2026-corrective-releases/" rel="nofollow">Source</a></p>

<p>The post <a rel="nofollow" href="https://mariadb.com/resources/blog/mariadb-community-server-q2-2026-corrective-releases/">MariaDB Community Server Q2 2026 corrective releases</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Migrate from Crunchy Data PostgreSQL Operator to Percona PostgreSQL Operator: Backup-Restore and PV Reuse</title>
      <link>https://www.percona.com/blog/migrate-from-crunchy-data-to-percona-postgresql-operator-backup-restore-pv-reuse/</link>
      <pubDate>Wed, 27 May 2026 12:02:55 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://www.percona.com/blog/">Blog - Percona</source>
      <description><![CDATA[<p>A Percona PostgreSQL operator pgBackRest restore is the simplest way to move off the Crunchy Data PostgreSQL Operator: take a full Crunchy backup, point the new Percona cluster’s dataSource at the existing pgBackRest archive, and the cluster bootstraps from it before its first start. This post covers that path, plus a second option, persistent-volume reuse, for cases … Continued<br />
The post Migrate from Crunchy Data PostgreSQL Operator to Percona PostgreSQL Operator: Backup-Restore and PV Reuse appeared first on Percona.</p>
<p>The post <a rel="nofollow" href="https://www.percona.com/blog/migrate-from-crunchy-data-to-percona-postgresql-operator-backup-restore-pv-reuse/">Migrate from Crunchy Data PostgreSQL Operator to Percona PostgreSQL Operator: Backup-Restore and PV Reuse</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p><img decoding="async" loading="lazy" class="aligncenter wp-image-47145 size-large" src="https://www.percona.com/wp-content/uploads/2026/05/hero-3-1024x375.png" alt="" width="1024" height="375"><br>
A Percona PostgreSQL operator pgBackRest restore is the simplest way to move off the Crunchy Data PostgreSQL Operator: take a full Crunchy backup, point the new Percona cluster&rsquo;s&nbsp;<code>dataSource</code>&nbsp;at the existing pgBackRest archive, and the cluster bootstraps from it before its first start. This post covers that path, plus a second option, persistent-volume reuse, for cases where you want to skip the data copy entirely.</p>
<p>This is&nbsp;<strong>part 3 of a 3-part series</strong>&nbsp;on running PostgreSQL on Kubernetes with a fully open-source operator.&nbsp;<a href="https://www.percona.com/blog/open-source-postgresql-operator-kubernetes-licensing-landscape/" rel="nofollow">Part 1</a>&nbsp;walked through the changing open-source landscape and announced the <strong>hard fork</strong> of the Crunchy Data PostgreSQL Operator into the fully independent <a href="https://github.com/percona/percona-postgresql-operator/tree/v3.0.0"><strong>Percona PostgreSQL Operator v3.0.0</strong></a>.&nbsp;<a href="https://www.percona.com/blog/migrate-from-crunchy-data-to-percona-postgresql-operator-standby-cluster" rel="nofollow">Part 2</a>&nbsp;covered the&nbsp;<strong>standby cluster</strong>&nbsp;method, the safest migration path when downtime budget is tight.</p>
<p>This post covers two simpler paths:</p>
<ul>
<li><strong>Backup and restore</strong>, the fastest if you can tolerate a short application-downtime window</li>
<li><strong>Persistent volume reuse</strong>, when you want to skip the data copy entirely and keep the existing PGDATA</li>
</ul>
<p>If you are landing here cold,&nbsp;<a href="https://www.percona.com/blog/not-all-open-source-is-equal-choosing-postgresql-operator-kubernetes-2026/" rel="nofollow">start with part 1</a> for the why, then read&nbsp;<a href="https://www.percona.com/blog/migrate-from-crunchy-data-to-percona-postgresql-operator-standby-cluster" rel="nofollow">Part 2</a>&nbsp;for the standby method. The rest of this post assumes you have already decided to migrate and want a tested playbook.</p>
<div class="markdown-heading">
<h3 class="heading-element">Tested with<a class="anchor-link" id="tested-with"></a></h3>
</div>
<table>
<thead>
<tr>
<th>Component</th>
<th>Version</th>
</tr>
</thead>
<tbody>
<tr>
<td>Crunchy Data PostgreSQL Kubernetes Operator</td>
<td>v5.8.x (tested on v5.8.7)</td>
</tr>
<tr>
<td>Percona PostgreSQL Kubernetes Operator</td>
<td>v3.x.x (tested on v3.0.0)</td>
</tr>
<tr>
<td>PostgreSQL</td>
<td>18 (must match between source and target)</td>
</tr>
<tr>
<td>Object storage</td>
<td>SeaweedFS (Apache-2.0), or any S3-compatible service. Required for the backup-and-restore method, optional for PV reuse.</td>
</tr>
<tr>
<td>Tools</td>
<td><code>kubectl</code>,&nbsp;<code>helm</code>&nbsp;(v3)</td>
</tr>
</tbody>
</table>
<p>Different versions may have slight differences in CR fields or behavior. Always consult the official documentation for the operator and PostgreSQL version you are running.</p>
<p>&nbsp;</p>
<div class="markdown-heading">
<h3 class="heading-element">What this post does NOT cover<a class="anchor-link" id="what-this-post-does-not-cover"></a></h3>
</div>
<ul>
<li>Application-side connection-string changes beyond updating to the new pgBouncer service</li>
<li>Schema-changing upgrades, major PostgreSQL version upgrades, or extension migrations</li>
<li>Crunchy enterprise-only features like TDE or pgBackRest custom encryption</li>
<li>Operating two operators against the same namespace before the hard fork. Use Percona PostgreSQL Operator v3.0.0 or higher.</li>
</ul>
<p>&nbsp;</p>
<div class="markdown-heading">
<h2 class="heading-element">1. Migration using backup and restore<a class="anchor-link" id="1-migration-using-backup-and-restore"></a></h2>
</div>
<p>This is often the fastest and simplest path, especially when you do not need a live standby. You take a full backup of the Crunchy source cluster, then create a Percona cluster that automatically restores from that backup before its first start.</p>
<p>Data written between the final backup and the application cutover is lost, so the migration window is the time between those two events. For a near-zero-downtime alternative, see&nbsp;<a href="https://www.percona.com/blog/migrate-from-crunchy-data-to-percona-postgresql-operator-standby-cluster/" rel="nofollow">part 2: standby cluster method</a>.</p>
<div class="markdown-heading">
<p>&nbsp;</p>
<h3 class="heading-element">Overview<br>
<img decoding="async" loading="lazy" class="aligncenter wp-image-47147 size-large" src="https://www.percona.com/wp-content/uploads/2026/05/backup-restore-1024x393.png" alt="" width="1024" height="393"><a class="anchor-link" id="overview"></a></h3>
<div class="markdown-heading">
&nbsp;
<h3 class="heading-element">Before you begin<a class="anchor-link" id="before-you-begin"></a></h3>
</div>
<p>Set the namespace once. Every command in this guide reads from this variable:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">export MIGRATION_NS=postgres-migration
kubectl create namespace $MIGRATION_NS</pre>

<div class="markdown-heading">
<p>&nbsp;</p>
<h3 class="heading-element">Deploy SeaweedFS<a class="anchor-link" id="deploy-seaweedfs"></a></h3>
</div>
<p>Skip this step if you already have an S3-compatible repository (AWS S3, GCS, Ceph). Update the endpoint and credentials in the YAML examples accordingly.</p>
<p>SeaweedFS provides an S3-compatible object store that runs inside Kubernetes. Both operators will use it as the shared pgBackRest WAL archive.</p>
<p><strong>TLS is required.</strong>&nbsp;pgBackRest always connects to S3 endpoints over HTTPS, even when&nbsp;<code>repo1-s3-verify-tls: "n"</code>&nbsp;is set (that flag skips certificate verification, it does not fall back to HTTP). The steps below generate a self-signed certificate and pass it to SeaweedFS via Helm values.</p>
<pre class="urvanov-syntax-highlighter-plain-tag"># Generate a self-signed TLS certificate for SeaweedFS S3
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 
  -keyout /tmp/seaweedfs.key 
  -out /tmp/seaweedfs.crt 
  -subj "/CN=seaweedfs-all-in-one"

kubectl -n $MIGRATION_NS create secret tls seaweedfs-s3-tls 
  --cert=/tmp/seaweedfs.crt 
  --key=/tmp/seaweedfs.key

helm repo add seaweedfs https://seaweedfs.github.io/seaweedfs/helm
helm repo update

helm install seaweedfs seaweedfs/seaweedfs 
  --namespace $MIGRATION_NS 
  --version 4.23.0 
  -f https://raw.githubusercontent.com/percona/percona-postgresql-operator/refs/heads/migration-from-crunchy-guide/e2e-tests/tests/migration-from-crunchy-backup-restore/examples/seaweedfs-values.yaml 
  --wait</pre>
<p>The Helm values file in the repo creates the&nbsp;<code>pg-migration</code>&nbsp;bucket on first start, so no separate&nbsp;<code>aws s3 mb</code>&nbsp;step is needed.</p>
<div class="markdown-heading">
&nbsp;
<h3 class="heading-element">Step 0. Create pgBackRest secrets<a class="anchor-link" id="step-0-create-pgbackrest-secrets"></a></h3>
</div>
<p>Both operators need credentials to read and write the shared SeaweedFS bucket. Apply the secrets from&nbsp;<a href="https://raw.githubusercontent.com/percona/percona-postgresql-operator/refs/heads/migration-from-crunchy-guide/e"><code>examples/01-pgbackrest-secrets.yaml</code></a>:</p>
<pre class="urvanov-syntax-highlighter-plain-tag"># Copy and edit the file first to set your credentials.
kubectl apply -n $MIGRATION_NS 
  -f https://raw.githubusercontent.com/percona/percona-postgresql-operator/refs/heads/migration-from-crunchy-guide/e2e-tests/tests/migration-from-crunchy-backup-restore/examples/01-pgbackrest-secrets.yaml</pre>
<p>Both contain the same SeaweedFS credentials (<em><code>pgmigration</code></em>&nbsp;/&nbsp;<em><code>pgmigration123</code></em>). For AWS S3, replace those with your IAM access key ID and secret access key.</p>
<p>&nbsp;</p>
<div class="markdown-heading">
<h3 class="heading-element">Step 1. Start with your existing Crunchy Data cluster<a class="anchor-link" id="step-1-start-with-your-existing-crunchy-data-cluster"></a></h3>
</div>
<p>If you already have a running Crunchy cluster, ensure its pgBackRest&nbsp;<code><em>repo1</em></code>&nbsp;points at the shared bucket. The&nbsp;<em><code>repo1-path</code></em>&nbsp;value must match the path that will be referenced in the Percona&nbsp;<em><code>dataSource.pgbackrest.global.repo1-path</code></em>&nbsp;field.</p>
<p>Optional: deploy the Crunchy operator for testing.&nbsp;<strong>The Helm install below is shown only as a quick way to reproduce this blog post&rsquo;s example. The migration steps in the rest of this post do not depend on how you deployed the source operator.</strong></p>
<pre class="urvanov-syntax-highlighter-plain-tag">helm install pgo 
  oci://registry.developers.crunchydata.com/crunchydata/pgo 
  -n $MIGRATION_NS 
  --version 5.8.7 
  --set singleNamespace=true 
  --wait</pre>
<p>To start a fresh source cluster for testing, apply&nbsp;<a href="https://raw.githubusercontent.com/percona/percona-postgresql-operator/refs/heads/migration-from-crunchy-guide/e2e-tests/tests/migration-from-crunchy-backup-restore/examples/02-crunchy-source-cluster.yaml"><code>examples/02-crunchy-source-cluster.yaml</code></a>:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">kubectl apply -n $MIGRATION_NS 
  -f https://raw.githubusercontent.com/percona/percona-postgresql-operator/refs/heads/migration-from-crunchy-guide/e2e-tests/tests/migration-from-crunchy-backup-restore/examples/02-crunchy-source-cluster.yaml</pre>
<p>The key pgBackRest settings:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">global:
  repo1-path: /crunchy-to-percona/repo1   # source repo referenced in Percona dataSource
  repo1-s3-uri-style: path                # required for path-style S3 endpoints (SeaweedFS, MinIO)
  repo1-s3-verify-tls: "n"                # skip TLS verification for self-signed cert; remove for AWS S3
repos:
  - name: repo1
    s3:
      bucket: pg-migration
      endpoint: seaweedfs-all-in-one.postgres-migration.svc.cluster.local:8443
      region: us-east-1</pre>
<p>Wait for the cluster and its pgBackRest stanza to be ready:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">kubectl wait pod 
  --selector postgres-operator.crunchydata.com/cluster=crunchy-source,postgres-operator.crunchydata.com/data=postgres 
  -n $MIGRATION_NS 
  --for=condition=Ready 
  --timeout=300s

kubectl wait postgrescluster/crunchy-source 
  -n $MIGRATION_NS 
  --for=jsonpath='{.status.pgbackrest.repos[0].stanzaCreated}'=true 
  --timeout=300s</pre>
<p>&nbsp;</p>
<h3>Step 2. Trigger a full backup (the migration cutover point)<a class="anchor-link" id="step-2-trigger-a-full-backup-the-migration-cutover-point"></a></h3>
<p>This is the backup the Percona cluster will restore from. Stop accepting writes on the application side before triggering it to ensure a consistent snapshot, or accept that data written after this backup will be lost.</p>
<pre class="urvanov-syntax-highlighter-plain-tag">kubectl annotate postgrescluster crunchy-source 
  -n $MIGRATION_NS 
  postgres-operator.crunchydata.com/pgbackrest-backup="$(date +%s)"

kubectl wait job 
  --selector postgres-operator.crunchydata.com/pgbackrest-backup=manual,postgres-operator.crunchydata.com/cluster=crunchy-source 
  -n $MIGRATION_NS 
  --for=condition=Complete 
  --timeout=600s</pre>
<p>&nbsp;</p>
<div class="markdown-heading">
<h3 class="heading-element">Step 3. Deploy the Percona Operator<a class="anchor-link" id="step-3-deploy-the-percona-operator"></a></h3>
</div>
<pre class="urvanov-syntax-highlighter-plain-tag">kubectl apply -n $MIGRATION_NS --server-side 
  -f https://raw.githubusercontent.com/percona/percona-postgresql-operator/refs/tags/v3.0.0/deploy/bundle.yaml

kubectl wait deployment percona-postgresql-operator 
  -n $MIGRATION_NS 
  --for=condition=Available 
  --timeout=120s</pre>

<div class="markdown-heading">
&nbsp;
<h3 class="heading-element">Step 4. Create the Percona cluster from the backup<a class="anchor-link" id="step-4-create-the-percona-cluster-from-the-backup"></a></h3>
</div>
<p>Apply&nbsp;<a href="https://raw.githubusercontent.com/percona/percona-postgresql-operator/refs/heads/migration-from-crunchy-guide/e2e-tests/tests/migration-from-crunchy-backup-restore/examples/03-percona-restored-cluster.yaml"><code>examples/03-percona-restored-cluster.yaml</code></a>:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">kubectl apply -n $MIGRATION_NS 
  -f https://raw.githubusercontent.com/percona/percona-postgresql-operator/refs/heads/migration-from-crunchy-guide/e2e-tests/tests/migration-from-crunchy-backup-restore/examples/03-percona-restored-cluster.yaml</pre>
<p>The key section that bootstraps the cluster from the Crunchy backup:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">dataSource:
  pgbackrest:
    stanza: db
    configuration:
      - secret:
          name: percona-pgbackrest-secret
    global:
      # Must match repo1-path in the Crunchy source cluster exactly.
      repo1-path: /crunchy-to-percona/repo1
      repo1-s3-uri-style: path
      repo1-s3-verify-tls: "n"
    repo:
      name: repo1
      s3:
        bucket: pg-migration
        endpoint: seaweedfs-all-in-one.postgres-migration.svc.cluster.local:8443
        region: us-east-1</pre>
<p>The Percona cluster&rsquo;s own backup repository must use a different path from the Crunchy source:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">backups:
  pgbackrest:
    global:
      repo1-path: /percona-restored/repo1   # different from Crunchy's path</pre>
<p>As soon as the Custom Resource is applied, the cluster is bootstrapped from the storage referenced in&nbsp;<em><code>dataSource</code></em>&nbsp;and then started. Once the cluster becomes ready, you can immediately create new backups; in this case,&nbsp;<em><code>repo1</code></em>&nbsp;from the&nbsp;<em><code>backups</code></em>&nbsp;section will be used as the target repository.</p>
<p>Wait for the cluster to reach ready state:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">kubectl wait perconapgcluster/percona-restored 
  -n $MIGRATION_NS 
  --for=jsonpath='{.status.state}'=ready 
  --timeout=600s</pre>
<p>Verify the data was restored successfully:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">PERCONA_PRIMARY=$(kubectl get pod -n $MIGRATION_NS 
  --selector postgres-operator.crunchydata.com/cluster=percona-restored,postgres-operator.crunchydata.com/role=primary 
  -o jsonpath='{.items[0].metadata.name}')

kubectl -n $MIGRATION_NS exec "${PERCONA_PRIMARY}" -c database -- 
  psql -t -c "SELECT pg_is_in_recovery();"</pre>
<p>Expected output:&nbsp;<em><code>f</code></em>. The cluster is the primary and accepts writes.<br>
&nbsp;</p>
<h3 class="heading-element">Step 5. Verify the cluster is healthy<a class="anchor-link" id="step-5-verify-the-cluster-is-healthy"></a></h3>

<pre class="urvanov-syntax-highlighter-plain-tag">kubectl wait perconapgcluster/percona-restored 
  -n $MIGRATION_NS 
  --for=jsonpath='{.status.state}'=ready 
  --timeout=600s

kubectl wait perconapgcluster/percona-restored 
  -n $MIGRATION_NS 
  --for=jsonpath='{.status.pgbackrest.repos[0].stanzaCreated}'=true 
  --timeout=300s</pre>

<div class="markdown-heading">
&nbsp;
<h3 class="heading-element">Step 6. Take a post-migration backup<a class="anchor-link" id="step-6-take-a-post-migration-backup"></a></h3>
</div>
<p>Apply&nbsp;<a href="https://raw.githubusercontent.com/percona/percona-postgresql-operator/refs/heads/migration-from-crunchy-guide/e2e-tests/tests/migration-from-crunchy-backup-restore/examples/04-post-migration-backup.yaml"><code>examples/04-post-migration-backup.yaml</code></a>:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">kubectl apply -n $MIGRATION_NS 
  -f https://raw.githubusercontent.com/percona/percona-postgresql-operator/refs/heads/migration-from-crunchy-guide/e2e-tests/tests/migration-from-crunchy-backup-restore/examples/04-post-migration-backup.yaml

kubectl wait perconapgbackup/post-migration-backup 
  -n $MIGRATION_NS 
  --for=jsonpath='{.status.state}'=Succeeded 
  --timeout=600s</pre>
<p>This creates a clean recovery baseline on the Percona cluster&rsquo;s own repository. All future PITR restores will use this backup, independent of the Crunchy archive.<br>
&nbsp;</p>
<h3 class="heading-element">Step 7. Reconnect your application<a class="anchor-link" id="step-7-reconnect-your-application"></a></h3>

<pre class="urvanov-syntax-highlighter-plain-tag">kubectl get service -n $MIGRATION_NS 
  --selector postgres-operator.crunchydata.com/cluster=percona-restored,postgres-operator.crunchydata.com/role=pgbouncer</pre>

<div class="markdown-heading">
&nbsp;
<h3 class="heading-element">Step 8. Clean up the Crunchy cluster<a class="anchor-link" id="step-8-clean-up-the-crunchy-cluster"></a></h3>
</div>
<p>Once the migration is verified and your application is connected to the new cluster:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">kubectl delete postgrescluster crunchy-source -n $MIGRATION_NS
helm uninstall pgo -n $MIGRATION_NS</pre>
<p>&nbsp;</p>
<div class="markdown-heading">
<h3 class="heading-element">Rollback<a class="anchor-link" id="rollback"></a></h3>
</div>
<p>Until Step 8, rollback is straightforward: switch the application connection string back to the Crunchy pgBouncer service. The Crunchy primary still holds the authoritative state because no writes were directed at the Percona cluster during the cutover (you stopped writes before Step 2). Any writes the application sent to the Percona cluster after cutover will not be present on Crunchy and would need to be replayed manually.</p>
<p>After Step 8, rollback requires restoring the Crunchy cluster from a backup, which is feasible because the original&nbsp;<em><code>repo1</code></em>&nbsp;is still in the bucket.</p>
<div class="markdown-heading">
&nbsp;
<h3 class="heading-element">Troubleshooting<a class="anchor-link" id="troubleshooting"></a></h3>
</div>
<p><strong><code>archive.info missing</code>.</strong>&nbsp;The&nbsp;<code><em>repo1-path</em></code>&nbsp;in&nbsp;<em><code>dataSource.pgbackrest.global</code></em>&nbsp;must match the Crunchy source cluster&rsquo;s&nbsp;<code>repo1-path</code>&nbsp;exactly:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">kubectl get postgrescluster crunchy-source -n $MIGRATION_NS 
  -o jsonpath='{.spec.backups.pgbackrest.global.repo1-path}'

kubectl get perconapgcluster percona-restored -n $MIGRATION_NS 
  -o jsonpath='{.spec.dataSource.pgbackrest.global.repo1-path}'</pre>
<p>&nbsp;</p>
<p><strong>Restore job fails with TLS errors.&nbsp;</strong>pgBackRest requires HTTPS even with&nbsp;<em><code>repo1-s3-verify-tls: "n"</code></em>. Verify SeaweedFS is reachable:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">kubectl run -i --rm s3-check 
  --image=perconalab/awscli 
  --restart=Never 
  -n $MIGRATION_NS 
  -- bash -c "
    AWS_ACCESS_KEY_ID=pgmigration 
    AWS_SECRET_ACCESS_KEY=pgmigration123 
    AWS_DEFAULT_REGION=us-east-1 
    aws --endpoint-url https://seaweedfs-all-in-one.${MIGRATION_NS}.svc.cluster.local:8443 
        --no-verify-ssl 
        s3 ls s3://pg-migration
  "</pre>
<p>&nbsp;</p>
<p><strong>Cluster stuck in restoring state.</strong>&nbsp;Check the pgBackRest restore job logs:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">kubectl logs 
  --selector postgres-operator.crunchydata.com/cluster=percona-restored,postgres-operator.crunchydata.com/pgbackrest-restore=percona-restored 
  -n $MIGRATION_NS 
  -c pgbackrest</pre>
<p><strong>Data missing after restore.</strong> The restore captures data up to the latest backup. If post-backup data is critical, re-run the backup on the Crunchy cluster after quiescing writes, then delete and recreate the Percona cluster to restore from the newer backup.</p>
<div class="markdown-heading">
&nbsp;
<h2 class="heading-element">2. Migration using existing persistent volumes<a class="anchor-link" id="2-migration-using-existing-persistent-volumes"></a></h2>
</div>
<p>This method reuses the Crunchy primary&rsquo;s PGDATA persistent volume directly. It avoids a full backup-restore cycle: you retain the Crunchy primary&rsquo;s PV, delete the Crunchy cluster, then create a Percona cluster whose PVC binds to that same PV. PostgreSQL starts on the existing data directory without any restore step.</p>
<p>It is useful when:</p>
<ul>
<li>you want to avoid copying data</li>
<li>your storage is very large</li>
<li>you must preserve the original data directory exactly</li>
<li>you removed the cluster but kept the PV</li>
</ul>
<p>&nbsp;</p>
<div class="markdown-heading">
<h3 class="heading-element">Overview<img decoding="async" loading="lazy" class="aligncenter wp-image-47148 size-large" src="https://www.percona.com/wp-content/uploads/2026/05/pv-reuse-1024x393.png" alt="" width="1024" height="393"><a class="anchor-link" id="overview"></a></h3>
<p>&nbsp;</p>
<h3 class="heading-element">Before you begin<a class="anchor-link" id="before-you-begin"></a></h3>

<pre class="urvanov-syntax-highlighter-plain-tag">export MIGRATION_NS=postgres-migration
kubectl create namespace $MIGRATION_NS</pre>

<div class="markdown-heading">
&nbsp;
<h3 class="heading-element">Step 1. Deploy the Crunchy and Percona operators<a class="anchor-link" id="step-1-deploy-the-crunchy-and-percona-operators"></a></h3>
</div>
<p>Both operators run in the same namespace. Crunchy PGO is uninstalled during the migration once the PV is retained.</p>
<blockquote>
<p><strong>Note (Crunchy)</strong>: The Helm install for Crunchy PGO below is shown only as a quick way to reproduce this blog post&rsquo;s example. If you are running Crunchy PGO in production, follow&nbsp;<a href="https://access.crunchydata.com/documentation/postgres-operator/latest/installation/" rel="nofollow">the official Crunchy Data documentation</a>&nbsp;for installation. The migration steps in the rest of this post do not depend on how you deployed the source operator.</p>
</blockquote>
<blockquote>
<p><strong>Note (Percona)</strong>: The&nbsp;<em><code>kubectl apply</code></em> of the Percona operator below uses defult configuration of <em><code>v3.0.0</code></em>&nbsp;from the operator repo for reproducibility of this guide. For production deployments, follow&nbsp;<a href="https://docs.percona.com/percona-operator-for-postgresql/latest/gke.html" rel="nofollow">the official Percona Operator for PostgreSQL installation documentation</a> to ensure the cluster configuration is properly sized and configured for your workload and traffic requirements.</p>
</blockquote>
<pre class="urvanov-syntax-highlighter-plain-tag">helm install pgo 
  oci://registry.developers.crunchydata.com/crunchydata/pgo 
  -n $MIGRATION_NS 
  --version 5.8.7 
  --set singleNamespace=true 
  --wait

kubectl apply -n $MIGRATION_NS --server-side 
  -f https://raw.githubusercontent.com/percona/percona-postgresql-operator/refs/tags/v3.0.0/deploy/bundle.yaml

kubectl wait deployment pgo 
  -n $MIGRATION_NS --for=condition=Available --timeout=120s

kubectl wait deployment percona-postgresql-operator 
  -n $MIGRATION_NS --for=condition=Available --timeout=120s</pre>

<div class="markdown-heading">
&nbsp;
<h3 class="heading-element">Step 2. Start the Crunchy source cluster<a class="anchor-link" id="step-2-start-the-crunchy-source-cluster"></a></h3>
</div>
<p>If you already have a running Crunchy cluster with&nbsp;<code><em>replicas: 1</em></code>, proceed to Step 3.</p>
<p>To start a fresh cluster for testing:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">kubectl apply -n $MIGRATION_NS 
  -f https://raw.githubusercontent.com/percona/percona-postgresql-operator/refs/heads/migration-from-crunchy-guide/e2e-tests/tests/migration-from-crunchy-pv/examples/01-crunchy-source-cluster.yaml

kubectl wait pod 
  --selector postgres-operator.crunchydata.com/cluster=crunchy-source,postgres-operator.crunchydata.com/role=master 
  -n $MIGRATION_NS 
  --for=condition=Ready 
  --timeout=300s</pre>

<div class="markdown-heading">
&nbsp;
<h3 class="heading-element">Step 3. Stop writes and identify the primary PV<a class="anchor-link" id="step-3-stop-writes-and-identify-the-primary-pv"></a></h3>
</div>
<p>Stop your application from writing to the database. This is the start of the downtime window. Then identify the primary pod, its PVC, and the backing PV:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">PRIMARY=$(kubectl get pod -n $MIGRATION_NS 
  --selector postgres-operator.crunchydata.com/cluster=crunchy-source,postgres-operator.crunchydata.com/role=master 
  -o jsonpath='{.items[0].metadata.name}')

PVC_NAME=$(kubectl get pod -n $MIGRATION_NS "${PRIMARY}" 
  -o jsonpath='{.spec.volumes[?(@.name=="postgres-data")].persistentVolumeClaim.claimName}')

PV_NAME=$(kubectl get pvc -n $MIGRATION_NS "${PVC_NAME}" 
  -o jsonpath='{.spec.volumeName}')

echo "Primary pod: ${PRIMARY}"
echo "PVC:         ${PVC_NAME}"
echo "PV:          ${PV_NAME}"</pre>

<div class="markdown-heading">
&nbsp;
<h3 class="heading-element">Step 4. Configure the source cluster to retain PVs<a class="anchor-link" id="step-4-configure-the-source-cluster-to-retain-pvs"></a></h3>
</div>
<p>If you want to delete the Crunchy source cluster but keep the persistent volumes, the PV reclaim policy must be set to&nbsp;<code><em>Retain</em></code>. For dynamically provisioned PersistentVolumes, the default reclaim policy is&nbsp;<em><code>Delete</code></em>, which removes the data once there are no more PersistentVolumeClaims associated with the PV.</p>
<pre class="urvanov-syntax-highlighter-plain-tag">kubectl patch pv "${PV_NAME}" 
  -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}'

kubectl get pv -n $MIGRATION_NS</pre>
<p>Delete the Crunchy cluster and uninstall PGO:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">kubectl patch postgrescluster crunchy-source -n $MIGRATION_NS 
  --type=json -p='[{"op":"remove","path":"/metadata/finalizers"}]' 2&gt;/dev/null || true

kubectl delete postgrescluster crunchy-source -n $MIGRATION_NS
helm uninstall pgo -n $MIGRATION_NS</pre>
<p>After the PVC is deleted, the PV enters&nbsp;<code><em>Released</em></code>&nbsp;state. A&nbsp;<em><code>Released</code></em>&nbsp;PV retains its old&nbsp;<code><em>claimRef</em></code>&nbsp;and cannot be claimed by a new PVC until it is cleared:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">kubectl patch pv "${PV_NAME}" --type=json 
  -p='[{"op":"remove","path":"/spec/claimRef"}]'

kubectl wait pv "${PV_NAME}" 
  --for=jsonpath='{.status.phase}'=Available 
  --timeout=60s</pre>
<p>Label the PV so the Percona PVC selector binds to it exclusively. This prevents accidental binding to another available volume:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">kubectl label pv "${PV_NAME}" percona-pv-migration=migrated</pre>
<p>&nbsp;</p>
<h3 class="heading-element">Step 5. Create the Percona cluster with the retained volume<a class="anchor-link" id="step-5-create-the-percona-cluster-with-the-retained-volume"></a></h3>

<pre class="urvanov-syntax-highlighter-plain-tag">kubectl apply -n $MIGRATION_NS 
  -f https://raw.githubusercontent.com/percona/percona-postgresql-operator/refs/heads/migration-from-crunchy-guide/e2e-tests/tests/migration-from-crunchy-pv/examples/02-percona-migrated-cluster.yaml</pre>
<p>The key section that binds the PVC to the labelled PV:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">instances:
  - name: instance1
    replicas: 1
    dataVolumeClaimSpec:
      selector:
        matchLabels:
          percona-pv-migration: migrated</pre>
<p>The Percona Operator creates a PVC with that selector. The PVC binds to the labelled PV, and PostgreSQL starts on the existing PGDATA directory with no restore needed. pgBackRest uses a local PVC-backed repository (<em><code>repo1.volume</code></em>), so no S3 credentials or external storage are required, but you can use S3 storage as well.</p>
<p>Wait for the cluster to become ready and verify the data is intact:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">kubectl wait perconapgcluster/percona-migrated 
  -n $MIGRATION_NS 
  --for=jsonpath='{.status.state}'=ready 
  --timeout=600s

PERCONA_PRIMARY=$(kubectl get pod -n $MIGRATION_NS 
  --selector postgres-operator.crunchydata.com/cluster=percona-migrated,postgres-operator.crunchydata.com/role=primary 
  -o jsonpath='{.items[0].metadata.name}')

kubectl -n $MIGRATION_NS exec "${PERCONA_PRIMARY}" -c database -- 
  psql -t -c "SELECT pg_is_in_recovery();"</pre>
<p>Expected output:&nbsp;<code><em>f</em></code>. The cluster is the primary and accepts writes.</p>
<div class="markdown-heading">
&nbsp;
<h3 class="heading-element">Step 6. Scale up replicas<a class="anchor-link" id="step-6-scale-up-replicas"></a></h3>
</div>
<p>The cluster started with a single replica to reuse the migrated PV. Once the primary is healthy, drop the PVC selector and scale out so the operator can provision fresh replica volumes from the storage class:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">kubectl patch perconapgcluster percona-migrated 
  --namespace $MIGRATION_NS 
  --type=json 
  -p='[
    {"op":"remove","path":"/spec/instances/0/dataVolumeClaimSpec/selector"},
    {"op":"replace","path":"/spec/instances/0/replicas","value":3}
  ]'

kubectl wait perconapgcluster/percona-migrated 
  --namespace $MIGRATION_NS 
  --for=jsonpath='{.status.state}'=ready 
  --timeout=300s</pre>
<p>Removing the selector here is important: leaving it in place would cause the new replica PVCs to fail provisioning because no other PV carries the migration label.<br>
&nbsp;</p>
<h3 class="heading-element">Step 7. Take a post-migration backup<a class="anchor-link" id="step-7-take-a-post-migration-backup"></a></h3>

<pre class="urvanov-syntax-highlighter-plain-tag">kubectl apply -n $MIGRATION_NS 
  -f https://raw.githubusercontent.com/percona/percona-postgresql-operator/refs/heads/migration-from-crunchy-guide/e2e-tests/tests/migration-from-crunchy-pv/examples/03-post-migration-backup.yaml

kubectl wait perconapgbackup/post-migration-backup 
  -n $MIGRATION_NS 
  --for=jsonpath='{.status.state}'=Succeeded 
  --timeout=600s</pre>
<p>This creates the first backup on the Percona cluster&rsquo;s local pgBackRest repository, establishing a baseline for future PITR restores.</p>
<div class="markdown-heading">
&nbsp;
<h3 class="heading-element">Step 8. Reconnect your application<a class="anchor-link" id="step-8-reconnect-your-application"></a></h3>

<pre class="urvanov-syntax-highlighter-plain-tag">kubectl get service -n $MIGRATION_NS 
  --selector postgres-operator.crunchydata.com/cluster=percona-migrated,postgres-operator.crunchydata.com/role=pgbouncer</pre>

<div class="markdown-heading">
&nbsp;
<h3 class="heading-element">Step 9. Cleanup<a class="anchor-link" id="step-9-cleanup"></a></h3>
</div>
<p>After the migration is verified, remove the migration label from the PV (Step 6 already removed the PVC selector that depended on it):</p>
<pre class="urvanov-syntax-highlighter-plain-tag">kubectl label pv "${PV_NAME}" percona-pv-migration-</pre>
<p>&nbsp;</p>
<div class="markdown-heading">
<h3 class="heading-element">Rollback<a class="anchor-link" id="rollback"></a></h3>
</div>
<p>PV migration is the least rollback-friendly of the three methods. Once the Percona cluster has started writing to the PGDATA directory, the original Crunchy timeline is gone. If you need a way back, take a Crunchy-side pgBackRest backup before Step 4 and treat that backup as your rollback point. Recovery is then a fresh Crunchy cluster restored from that backup.</p>
<div class="markdown-heading">
&nbsp;
<h3 class="heading-element">Troubleshooting<a class="anchor-link" id="troubleshooting"></a></h3>
</div>
<p><strong>PVC stays in&nbsp;<code>Pending</code>&nbsp;state.</strong>&nbsp;The PVC selector did not match the labelled PV. Verify the label and PV phase:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">kubectl get pv "${PV_NAME}" --show-labels
kubectl get pv "${PV_NAME}" -o jsonpath='{.status.phase}'</pre>
<p><strong>PostgreSQL fails to start (data directory errors).</strong>&nbsp;Check the database container logs:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">kubectl -n $MIGRATION_NS logs "${PERCONA_PRIMARY}" -c database</pre>
<p>If the Crunchy cluster was shut down uncleanly, there may be incomplete WAL. Patroni will attempt crash recovery automatically; check the logs for progress.</p>
<p><strong>PV was deleted before setting&nbsp;<code>Retain</code>.</strong>&nbsp;If the PV was deleted along with the PVC (default&nbsp;<code>Delete</code>&nbsp;policy), the data is gone and PV migration is no longer possible. Use the backup-and-restore migration above, restoring from the most recent pgBackRest backup.</p>
<p>&nbsp;</p>
<div class="markdown-heading">
<h3 class="heading-element">Conclusion<a class="anchor-link" id="conclusion"></a></h3>
</div>
<p>Two more migration paths from the Crunchy Data PostgreSQL Operator to the fully open-source Percona PostgreSQL Operator. Combined with <a href="https://www.percona.com/blog/migrate-from-crunchy-data-to-percona-postgresql-operator-standby-cluster" rel="nofollow">Part 2</a>, the series gives you three production-tested options:</p>
<ul>
<li><strong>Standby cluster</strong>&nbsp;(part 2): near-zero downtime via streaming replication and pgBackRest standby</li>
<li><strong>Backup and restore</strong>&nbsp;(this post): the simplest path, restoring directly from a Crunchy pgBackRest backup</li>
<li><strong>Persistent volume reuse</strong>&nbsp;(this post): when you want to keep storage and skip the data copy</li>
</ul>
<p>All three approaches are safe, predictable, and reversible, with the rollback caveats noted in each section. Because Percona&rsquo;s operator, images, and tooling are 100 percent open source, you keep full control: you can always migrate back to the Crunchy operator, or out to another open-source operator (Zalando, StackGres, CloudNativePG) using the same patterns. That last journey is a topic for a future post.</p>
<p>This post covers basic deployment patterns and simplified configuration examples. If your environment uses custom images, Crunchy enterprise features, or otherwise needs tailored migration steps, contact the Percona team and we will help you plan and execute the move.</p>
<p>&nbsp;</p>
<div class="markdown-heading">
<h3 class="heading-element">Try It Out<a class="anchor-link" id="try-it-out"></a></h3>
</div>
<ul>
<li><strong>Percona Operator for PostgreSQL docs</strong>: <a href="https://docs.percona.com/percona-operator-for-postgresql/latest/">https://docs.percona.com/percona-operator-for-postgresql/latest/</a></li>
<li><strong>GitHub</strong>:&nbsp;<a href="https://github.com/percona/percona-postgresql-operator">https://github.com/percona/percona-postgresql-operator</a></li>
<li><strong>Public roadmap</strong>:&nbsp;<a href="https://github.com/orgs/percona/projects/10/views/6">https://github.com/orgs/percona/projects/10/views/6</a></li>
<li><strong>Community Forum</strong>:&nbsp;<a href="https://forums.percona.com/c/postgresql/percona-kubernetes-operator-for-postgresql/68" rel="nofollow">https://forums.percona.com/c/postgresql/percona-kubernetes-operator-for-postgresql/68</a></li>
</ul>
</div>
</div>
</div>
<p>The post <a href="https://www.percona.com/blog/migrate-from-crunchy-data-to-percona-postgresql-operator-backup-restore-pv-reuse/">Migrate from Crunchy Data PostgreSQL Operator to Percona PostgreSQL Operator: Backup-Restore and PV Reuse</a> appeared first on <a href="https://www.percona.com">Percona</a>.</p>

<p>The post <a rel="nofollow" href="https://www.percona.com/blog/migrate-from-crunchy-data-to-percona-postgresql-operator-backup-restore-pv-reuse/">Migrate from Crunchy Data PostgreSQL Operator to Percona PostgreSQL Operator: Backup-Restore and PV Reuse</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Virtuozzo Renews Sponsorship of MariaDB Foundation</title>
      <link>https://mariadb.org/virtuozzo-renews-sponsorship-of-mariadb-foundation/</link>
      <pubDate>Wed, 27 May 2026 10:48:37 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.org/">MariaDB.org</source>
      <description><![CDATA[<p>We are delighted to announce that Virtuozzo has renewed its sponsorship of MariaDB Foundation.<br />
Virtuozzo has been a long-standing supporter of open infrastructure, service providers, and cloud platforms, and we are very pleased to continue strengthening our collaboration. …<br />
Continue reading \"Virtuozzo Renews Sponsorship of MariaDB Foundation\"<br />
The post Virtuozzo Renews Sponsorship of MariaDB Foundation appeared first on MariaDB.org.</p>
<p>The post <a rel="nofollow" href="https://mariadb.org/virtuozzo-renews-sponsorship-of-mariadb-foundation/">Virtuozzo Renews Sponsorship of MariaDB Foundation</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>We are delighted to announce that <a href="https://www.virtuozzo.com/">Virtuozzo</a> has renewed its sponsorship of MariaDB Foundation.<br>
Virtuozzo has been a long-standing supporter of open infrastructure, service providers, and cloud platforms, and we are very pleased to continue strengthening our collaboration. &hellip; </p>
<p class="link-more"><a href="https://mariadb.org/virtuozzo-renews-sponsorship-of-mariadb-foundation/" class="more-link">Continue reading<span class="screen-reader-text"> &ldquo;Virtuozzo Renews Sponsorship of MariaDB Foundation&rdquo;</span></a></p>
<p>The post <a rel="nofollow" href="https://mariadb.org/virtuozzo-renews-sponsorship-of-mariadb-foundation/">Virtuozzo Renews Sponsorship of MariaDB Foundation</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>

<p>The post <a rel="nofollow" href="https://mariadb.org/virtuozzo-renews-sponsorship-of-mariadb-foundation/">Virtuozzo Renews Sponsorship of MariaDB Foundation</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>How MariaDB Cloud Optimizes Database Resilience and Cost: A Deep Dive into High Availability</title>
      <link>https://mariadb.com/resources/blog/how-mariadb-cloud-optimizes-database-resilience-and-cost-a-deep-dive-into-high-availability/</link>
      <pubDate>Tue, 26 May 2026 17:49:30 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.com/">MariaDB</source>
      <description><![CDATA[<p>MariaDB has long been the backbone of mission-critical applications, valued for its rich feature set, developer-friendly SQL dialect and a […]</p>
<p>The post <a rel="nofollow" href="https://mariadb.com/resources/blog/how-mariadb-cloud-optimizes-database-resilience-and-cost-a-deep-dive-into-high-availability/">How MariaDB Cloud Optimizes Database Resilience and Cost: A Deep Dive into High Availability</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>MariaDB has long been the backbone of mission-critical applications, valued for its rich feature set, developer-friendly SQL dialect and a massive global ecosystem of tools. But as workloads migrate to the cloud, the conversation has shifted from simple database features to operational excellence. Today, the priority is on seamless scaling, rock-solid security, effortless replication&hellip;</p>
<p><a href="https://mariadb.com/resources/blog/how-mariadb-cloud-optimizes-database-resilience-and-cost-a-deep-dive-into-high-availability/" rel="nofollow">Source</a></p>

<p>The post <a rel="nofollow" href="https://mariadb.com/resources/blog/how-mariadb-cloud-optimizes-database-resilience-and-cost-a-deep-dive-into-high-availability/">How MariaDB Cloud Optimizes Database Resilience and Cost: A Deep Dive into High Availability</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>How Procurement Leaders Realize ROI from Open Source Databases</title>
      <link>https://www.percona.com/blog/how-procurement-leaders-realize-roi-from-open-source-databases/</link>
      <pubDate>Tue, 26 May 2026 15:20:50 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://www.percona.com/blog/">Blog - Percona</source>
      <description><![CDATA[<p>Database purchases are often considered just another IT expense. The primary concerns are limited to license fees and sign support contracts. But this mindset ignores hidden costs like downtime, excess capacity, rising renewal fees, and data transfer charges. The financial sector particularly suffers, as proprietary databases hinder system updates for compliance and real-time AI, impose … Continued<br />
The post How Procurement Leaders Realize ROI from Open Source Databases appeared first on Percona.</p>
<p>The post <a rel="nofollow" href="https://www.percona.com/blog/how-procurement-leaders-realize-roi-from-open-source-databases/">How Procurement Leaders Realize ROI from Open Source Databases</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>Database purchases are often considered just another IT expense. The primary concerns are limited to license fees and sign support contracts. But this mindset ignores hidden costs like downtime, excess capacity, rising renewal fees, and data transfer charges.</p>
<p>The financial sector particularly suffers, as proprietary databases hinder system updates for compliance and real-time AI, impose rigid pricing, and shift operational risk to the buyer.</p>
<p>Procurement leaders are starting to see this problem. Over <a href="https://www.percona.com/blog/alternatives-to-cloud-dbaas-what-to-look-for/">74% of Database as a Service (DBaaS)</a> users cite high and unpredictable costs as their top challenge due to proprietary pricing structures. Meanwhile, the open source database market is projected to reach <a href="https://market.us/report/open-source-database-market/">$63.48 billion by 2034</a>, signaling a major industry shift.</p>
<p>Switching to open source databases offers procurement teams better financial control, allowing spending to be measured and predicted like any other asset.</p>
<p>This article provides a framework for procurement leaders to realize the ROI of open source databases. It explains how to move beyond license-focused sourcing to a strategy that prioritizes risk reduction, spend predictability, and vendor optionality.</p>
<h2>The procurement blind spot: What database TCO really includes<a class="anchor-link" id="the-procurement-blind-spot-what-database-tco-really-includes"></a></h2>
<p>License fees often become the total cost baseline in many sourcing cycles. But that license cost is only a fraction of the true database Total Cost of Ownership (TCO). The massive operational and strategic costs are hidden beneath the surface. The cost drivers show up in six areas:</p>
<ul>
<li><strong>Outage and SLA penalties:</strong> Downtime incurred due to vendor-managed recovery or architecture constraints.</li>
<li><strong>Forced over-provisioning:</strong> Licensing models that require institutions to buy capacity they may not fully use (because licenses are sold in &ldquo;blocks&rdquo; or &ldquo;cores&rdquo;). If your workload requires 9 cores, you are often forced to pay for 16.</li>
<li><strong>Escalating renewal pricing:</strong> Per-core or per-instance fees that climb with infrastructure growth, unrelated to feature value.</li>
<li><strong>Data egress fees and platform taxes:</strong> Cloud DBaaS charges for cross-region replication, data exports, backups, and traffic that accumulate unpredictably.</li>
<li><strong>Staffing and operational overhead:</strong> Database administrators and Site Reliability Engineers (SREs) dedicating time to tuning, patching, and managing vendor-specific tooling.</li>
<li><strong>Migration and switching costs:</strong> The financial and technical burden of moving data if vendor changes or licensing terms shift.</li>
</ul>
<h3>Downtime as a financial liability (Not a technical issue)<a class="anchor-link" id="downtime-as-a-financial-liability-not-a-technical-issue"></a></h3>
<p>Procurement teams may not always be the primary owners of downtime risk, but they often influence it through vendor selection, contract terms, and support coverage. Because outages carry measurable business impact, support responsiveness and recovery capability should be evaluated as a financial exposure.</p>
<p>For example, critical-incident response and restoration expectations must be defined and aligned with the organization&rsquo;s risk tolerance. If not, the institution may be accepting avoidable financial and operational exposure during high-severity events.</p>
<p>The financial model is simple:</p>
<p><strong>(Incident Frequency) &times; (Incident Duration) &times; (Cost Per Hour) = Annual Risk Exposure</strong></p>
<p>For a bank with three major outages per year, averaging 4 hours each, with a $500K/hour impact:</p>
<p><strong>3 &times; 4 &times; $500,000 = $6 million in annual downtime risk</strong></p>
<p>Open source works best when supported by vendor-agnostic experts like <a href="https://www.percona.com/services/support/policies">Percona&rsquo;s</a>. It allows procurement to source support that focuses on restoring service across the entire stack, rather than defending a specific piece of software.</p>
<h3>Cost predictability vs. vendor-driven cost escalation<a class="anchor-link" id="cost-predictability-vs-vendor-driven-cost-escalation"></a></h3>
<p>Budget forecasting becomes impossible when database costs are unpredictable. Yet proprietary licensing introduces multiple mechanisms that undermine forecast accuracy and negatively affect business success.</p>
<ul>
<li><strong>The scaling penalty:</strong> As your customer base grows and you add more hardware, your software costs increase exponentially because of per-core or per-socket licensing.</li>
<li><strong>Tier creep:</strong> You might start on a Standard tier, but as soon as you need a critical security feature like advanced encryption or granular auditing for DORA <a href="https://www.eiopa.europa.eu/digital-operational-resilience-act-dora_en">(Digital Operational Resilience Act)</a> compliance, you are forced into an Enterprise tier that can cost more.</li>
</ul>
<p>In contrast, open source separates the software cost from growth. If you double your infrastructure to handle peak trading volumes, your software cost remains zero. It lets procurement provide the business with a linear, predictable cost model (you only pay for the infrastructure you use and the expertise required to run it).</p>
<h3>Vendor lock-in and contract leverage<a class="anchor-link" id="vendor-lock-in-and-contract-leverage"></a></h3>
<p>The primary objective of a sales team from a proprietary vendor is to make customers more committed to their products. The more vendor-specific features you use, the harder it is for procurement to negotiate when renewing the contract. Over time:</p>
<ul>
<li><strong>Switching costs add up:</strong> Data migration, changing schemas, and application changes create high barriers to leaving.</li>
<li><strong>Vendor leverage grows:</strong> As integration deepens, alternatives become more costly, reducing competition in renewal negotiations.</li>
<li><strong>Renewal pricing rises:</strong> With fewer alternatives, vendors increase renewal fees, confident that institutions cannot easily leave.</li>
</ul>
<p><a href="https://www.percona.com/blog/redis-users-want-a-change/">Percona&rsquo;s research on Redis</a> users shows that nearly 75% have considered or tested alternatives when licensing terms change, but most couldn&rsquo;t really switch. This is vendor lock-in at its most destructive, as institutions resent the vendor but cannot leave.</p>
<p>Open source gives institutions more options (restores vendor optionality). Procurement can regain power through:</p>
<ul>
<li><strong>Multi-vendor support:</strong> If one support provider underperforms or raises prices, you can move your support contract to another provider without migrating your data.</li>
<li><strong>Deployment flexibility:</strong> Open source can run on-premise, in any cloud (AWS, Azure, GCP), or in a hybrid model.</li>
<li><strong>Lower switching costs:</strong> Since open source uses standard protocols, it is easier to find talent and tools that work across the stack, and reduce the exit cost of any single relationship.</li>
</ul>
<h3>Operational efficiency as a budget control mechanism<a class="anchor-link" id="operational-efficiency-as-a-budget-control-mechanism"></a></h3>
<p>Database operations often increase operating expenses. When teams react to problems rather than prevent them, labor costs rise without notice. Inefficient database management raises labor costs in two ways:</p>
<ul>
<li><strong>Specialized labor scarcity:</strong> Finding a specialist for a proprietary database is expensive.</li>
<li><strong>Reactive engineering:</strong> When database performance is poor, teams spend more time fixing issues instead of building new products.</li>
</ul>
<p>Switching to an open-source system with integrated management tools, like <a href="https://www.percona.com/software/database-tools/percona-monitoring-and-management">Percona Monitoring and Management</a>, can help the organization save valuable engineering time.</p>
<p>For example, if a 10-person engineering team spends 20% of their time on manual database maintenance, that&rsquo;s like paying two full-time employees just to keep things running. Improving tools and support reduces this work and provides immediate operational ROI.</p>
<h3>Data egress fees: The hidden variable cost<a class="anchor-link" id="data-egress-fees-the-hidden-variable-cost"></a></h3>
<p>In cloud services, it&rsquo;s usually free to get your data in, but costs can skyrocket when you want to get your data out. Many managed proprietary DBaaS platforms are designed to trap your data. They make it easy to scale up, but charge massive data egress fees if you want to move that data to a third-party analytics tool or a different cloud provider.</p>
<p>Open source databases, particularly when run on <a href="https://www.percona.com/blog/managed-database-vs-kubernetes-taking-back-control-of-your-cloud-costs-and-agility/">Kubernetes</a> or self-managed infrastructure, give you full control over the data path. With that control, procurement and platform stakeholders can design data flows that reduce unnecessary cross-cloud transfers and help minimize egress fees.</p>
<h3>Annualized ROIs Summary for procurement<a class="anchor-link" id="annualized-rois-summary-for-procurement"></a></h3>
<p>When presenting the move to open source to the executive team, procurement should frame the benefits across the following financial pillars:</p>
<table style="border-collapse: collapse;width: 100%">
<thead>
<tr>
<th style="border: 1px solid #ccc;padding: 10px 12px;text-align: left;background-color: #f4f4f4">ROI Lever</th>
<th style="border: 1px solid #ccc;padding: 10px 12px;text-align: left;background-color: #f4f4f4">Procurement outcome</th>
<th style="border: 1px solid #ccc;padding: 10px 12px;text-align: left;background-color: #f4f4f4">Financial impact</th>
</tr>
</thead>
<tbody>
<tr>
<td style="border: 1px solid #ccc;padding: 10px 12px"><strong>Risk avoidance</strong></td>
<td style="border: 1px solid #ccc;padding: 10px 12px">Reduced downtime frequency and duration.</td>
<td style="border: 1px solid #ccc;padding: 10px 12px">Lowered black swan event liability.</td>
</tr>
<tr>
<td style="border: 1px solid #ccc;padding: 10px 12px"><strong>Spend control</strong></td>
<td style="border: 1px solid #ccc;padding: 10px 12px">Removal of license multipliers.</td>
<td style="border: 1px solid #ccc;padding: 10px 12px">Predictable, linear cost growth.</td>
</tr>
<tr>
<td style="border: 1px solid #ccc;padding: 10px 12px"><strong>Leverage</strong></td>
<td style="border: 1px solid #ccc;padding: 10px 12px">Multi-vendor support options.</td>
<td style="border: 1px solid #ccc;padding: 10px 12px">Stronger renewal negotiating power.</td>
</tr>
<tr>
<td style="border: 1px solid #ccc;padding: 10px 12px"><strong>Productivity</strong></td>
<td style="border: 1px solid #ccc;padding: 10px 12px">Reduced manual DB management.</td>
<td style="border: 1px solid #ccc;padding: 10px 12px">Reclaiming expensive engineering hours.</td>
</tr>
</tbody>
</table>
<h2>
Why open source aligns with procurement objectives<a class="anchor-link" id="why-open-source-aligns-with-procurement-objectives"></a></h2>
<p>Modern procurement is about governance, compliance, and strategic alignment. Open source databases align with these goals better than proprietary ones:</p>
<ul>
<li><strong>No licensing premiums for scale or performance.</strong> A 10x increase in data does not mean 10x higher license fees.</li>
<li><strong>Transparent, auditable cost structures.</strong> Procurement knows exactly what they are paying for.</li>
<li><strong>Support can be competitively sourced.</strong> Institutions are not locked into a single software vendor.</li>
<li><strong>Better compliance and security.</strong> Open code enables internal security reviews, transparency for auditors, and helps meet regulatory requirements.</li>
</ul>
<h2>Operating open source with procurement-grade assurance<a class="anchor-link" id="operating-open-source-with-procurement-grade-assurance"></a></h2>
<p>A common objection to open source is that it&rsquo;s unsupported. Procurement teams need operational assurance, confidence that open source environments meet the same regulatory, availability, and financial standards as proprietary systems.</p>
<p>When evaluating a support partner, procurement should require:</p>
<ul>
<li><strong>SLA clarity:</strong> Specific, contractually backed response and resolution times.</li>
<li><strong>Multi-database coverage:</strong> One contract that covers MySQL, PostgreSQL, and MongoDB to reduce contract sprawl.</li>
<li><strong>Regulated-environment experience:</strong> A partner who understands PCI-DSS, SOC2, and the high-compliance needs of finance.</li>
</ul>
<p>Percona meets all of these criteria and offers procurement with a partner that turns technical operations into financial metrics.</p>
<h2>Where Percona fits<a class="anchor-link" id="where-percona-fits"></a></h2>
<p>Percona operationalizes open source databases for regulated, mission-critical environments. It delivers measurable outcomes across four strategic dimensions for procurement teams:</p>
<h3>Independent, vendor-neutral support model<a class="anchor-link" id="independent-vendor-neutral-support-model"></a></h3>
<p>Percona provides <a href="https://www.percona.com/services/support">technology-agnostic support</a> across MySQL, PostgreSQL, MongoDB, MariaDB, and Valkey. It operates independently of cloud providers and database vendors, supporting on premises, cloud, and hybrid environments. This vendor neutrality ensures institutions maintain full control over technology choices without being locked into specific platforms or ecosystems.</p>
<h3>Predictable support costs without licensing dependency<a class="anchor-link" id="predictable-support-costs-without-licensing-dependency"></a></h3>
<p><a href="https://www.percona.com/blog/why-companies-are-saying-no-to-proprietary-software-including-mongodb/">Percona&rsquo;s pricing model</a> decouples support costs from database licensing and creates transparent, forecastable expenses. While proprietary databases force organizations to pay escalating per-core or usage-based fees, Percona&rsquo;s support subscriptions operate independently of infrastructure growth. For example, organizations like <a href="https://experience.percona.com/case-study/bbva/">BBVA</a> reduced licensing and support costs while simultaneously improving backup performance by 20% after migrating to Percona Server for MongoDB.</p>
<h3>Proven experience supporting regulated financial systems<a class="anchor-link" id="proven-experience-supporting-regulated-financial-systems"></a></h3>
<p>Percona supports regulated financial systems, including Fortune 500 companies and government agencies, and meets <a href="https://experience.percona.com/postgresql/postgre-sql-security-solution-brief/">compliance standards</a> such as HIPAA, PCI DSS, GDPR, and DORA EU.</p>
<p>Major financial services implementations include:</p>
<ul>
<li><strong><a href="https://www.percona.com/about-percona/case-studies/merchant-warrior-counts-on-percona-for-critical-availability">Merchant Warrior</a>:</strong> Australia&rsquo;s payments gateway relies on Percona for critical MySQL availability, supporting millions of transactions across 30,000+ customers.</li>
<li><strong><a href="https://www.percona.com/about-percona/newsroom/press-releases/multipay-group-chooses-percona-database-management">MultiPay</a> and <a href="https://www.percona.com/about-percona/case-studies/bukalapak">Bukalapak</a>:</strong> Financial services and e-commerce platforms leveraging Percona&rsquo;s support to maintain high availability and optimize deployment performance.</li>
</ul>
<h2>Conclusion: Database performance as a spend control strategy<a class="anchor-link" id="conclusion-database-performance-as-a-spend-control-strategy"></a></h2>
<p>Databases have evolved from technical infrastructure into financial assets. Their uptime, performance, and flexibility influence costs, vendor leverage, and operational resilience. For procurement, buying databases is a strategic investment to control expenses and manage risks.</p>
<p>Organizations gain predictable costs, measurable ROI, vendor optionality, and long-term operational control by choosing open-source databases and partnering with Percona. These advantages compound over time, while proprietary systems often fall short.</p>
<p>Get started with <a href="https://www.percona.com/software/percona-operators">Percona Operators</a> and see how consistency, scale, and freedom come together.</p>
<p>The post <a href="https://www.percona.com/blog/how-procurement-leaders-realize-roi-from-open-source-databases/">How Procurement Leaders Realize ROI from Open Source Databases</a> appeared first on <a href="https://www.percona.com">Percona</a>.</p>

<p>The post <a rel="nofollow" href="https://www.percona.com/blog/how-procurement-leaders-realize-roi-from-open-source-databases/">How Procurement Leaders Realize ROI from Open Source Databases</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>ProxySQL joins MariaDB Foundation as Silver Sponsor</title>
      <link>https://mariadb.org/proxysql-joins-mariadb-foundation/</link>
      <pubDate>Tue, 26 May 2026 06:11:40 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.org/">MariaDB.org</source>
      <description><![CDATA[<p>We are very pleased to welcome ProxySQL as a Silver Sponsor of the MariaDB Foundation.<br />
ProxySQL is the leading proxy for MySQL and has recently focused on supporting more and more of MariaDB, both with the Proxy and with other open-source projects ProxySQL is stewarding, like dbdeployer and orchestrator. …<br />
Continue reading \"ProxySQL joins MariaDB Foundation as Silver Sponsor\"<br />
The post ProxySQL joins MariaDB Foundation as Silver Sponsor appeared first on MariaDB.org.</p>
<p>The post <a rel="nofollow" href="https://mariadb.org/proxysql-joins-mariadb-foundation/">ProxySQL joins MariaDB Foundation as Silver Sponsor</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>We are very pleased to welcome <a href="https://proxysql.com/">ProxySQL</a> as a Silver Sponsor of the MariaDB Foundation.<br>
ProxySQL is the leading proxy for MySQL and has recently focused on supporting more and more of MariaDB, both with the Proxy and with other open-source projects ProxySQL is stewarding, like <a href="http://github.com/ProxySQL/dbdeployer">dbdeployer</a> and <a href="https://github.com/ProxySQL/orchestrator">orchestrator</a>. &hellip; </p>
<p class="link-more"><a href="https://mariadb.org/proxysql-joins-mariadb-foundation/" class="more-link">Continue reading<span class="screen-reader-text"> &ldquo;ProxySQL joins MariaDB Foundation as Silver Sponsor&rdquo;</span></a></p>
<p>The post <a rel="nofollow" href="https://mariadb.org/proxysql-joins-mariadb-foundation/">ProxySQL joins MariaDB Foundation as Silver Sponsor</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>

<p>The post <a rel="nofollow" href="https://mariadb.org/proxysql-joins-mariadb-foundation/">ProxySQL joins MariaDB Foundation as Silver Sponsor</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>ProxySQL joins MariaDB Foundation as Silver Sponsor</title>
      <link>https://mariadb.org/psql-joins-mariadb-foundation/</link>
      <pubDate>Tue, 26 May 2026 06:10:00 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.org/">MariaDB.org</source>
      <description><![CDATA[<p>We are very pleased to welcome ProxySQL as a Silver Sponsor of the MariaDB Foundation.<br />
ProxySQL is the leading proxy for MySQL and has recently focused on supporting more and more of MariaDB, both with the Proxy and with other open-source projects ProxySQL is stewarding, like dbdeployer and orchestrator. …<br />
Continue reading \"ProxySQL joins MariaDB Foundation as Silver Sponsor\"<br />
The post ProxySQL joins MariaDB Foundation as Silver Sponsor appeared first on MariaDB.org.</p>
<p>The post <a rel="nofollow" href="https://mariadb.org/psql-joins-mariadb-foundation/">ProxySQL joins MariaDB Foundation as Silver Sponsor</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>We are very pleased to welcome <a href="https://proxysql.com/">ProxySQL</a> as a Silver Sponsor of the MariaDB Foundation.<br>
ProxySQL is the leading proxy for MySQL and has recently focused on supporting more and more of MariaDB, both with the Proxy and with other open-source projects ProxySQL is stewarding, like <a href="http://github.com/ProxySQL/dbdeployer">dbdeployer</a> and <a href="https://github.com/ProxySQL/orchestrator">orchestrator</a>. &hellip; </p>
<p class="link-more"><a href="https://mariadb.org/psql-joins-mariadb-foundation/" class="more-link">Continue reading<span class="screen-reader-text"> &ldquo;ProxySQL joins MariaDB Foundation as Silver Sponsor&rdquo;</span></a></p>
<p>The post <a rel="nofollow" href="https://mariadb.org/psql-joins-mariadb-foundation/">ProxySQL joins MariaDB Foundation as Silver Sponsor</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>

<p>The post <a rel="nofollow" href="https://mariadb.org/psql-joins-mariadb-foundation/">ProxySQL joins MariaDB Foundation as Silver Sponsor</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>ProxySQL joins MariaDB Foundation as Silver Sponsor</title>
      <link>https://mariadb.org/new-sponsor-proxysql-mariadb-foundation/</link>
      <pubDate>Tue, 26 May 2026 06:10:00 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.org/">MariaDB.org</source>
      <description><![CDATA[<p>We are very pleased to welcome ProxySQL as a Silver Sponsor of the MariaDB Foundation.<br />
ProxySQL is the leading proxy for MySQL and has recently focused on supporting more and more of MariaDB, both with the Proxy and with other open-source projects ProxySQL is stewarding, like dbdeployer and orchestrator. …<br />
Continue reading \"ProxySQL joins MariaDB Foundation as Silver Sponsor\"<br />
The post ProxySQL joins MariaDB Foundation as Silver Sponsor appeared first on MariaDB.org.</p>
<p>The post <a rel="nofollow" href="https://mariadb.org/new-sponsor-proxysql-mariadb-foundation/">ProxySQL joins MariaDB Foundation as Silver Sponsor</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>We are very pleased to welcome <a href="https://proxysql.com/">ProxySQL</a> as a Silver Sponsor of the MariaDB Foundation.<br>
ProxySQL is the leading proxy for MySQL and has recently focused on supporting more and more of MariaDB, both with the Proxy and with other open-source projects ProxySQL is stewarding, like <a href="http://github.com/ProxySQL/dbdeployer">dbdeployer</a> and <a href="https://github.com/ProxySQL/orchestrator">orchestrator</a>. &hellip; </p>
<p class="link-more"><a href="https://mariadb.org/new-sponsor-proxysql-mariadb-foundation/" class="more-link">Continue reading<span class="screen-reader-text"> &ldquo;ProxySQL joins MariaDB Foundation as Silver Sponsor&rdquo;</span></a></p>
<p>The post <a rel="nofollow" href="https://mariadb.org/new-sponsor-proxysql-mariadb-foundation/">ProxySQL joins MariaDB Foundation as Silver Sponsor</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>

<p>The post <a rel="nofollow" href="https://mariadb.org/new-sponsor-proxysql-mariadb-foundation/">ProxySQL joins MariaDB Foundation as Silver Sponsor</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Drupal recommends MariaDB</title>
      <link>https://mariadb.org/drupal-recommends-mariadb/</link>
      <pubDate>Mon, 25 May 2026 11:29:10 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.org/">MariaDB.org</source>
      <description><![CDATA[<p>MariaDB is now clearly listed as the recommended database in Drupal’s official documentation. Following community discussion on Drupal.org, the Database server requirements now lists MariaDB first, and identifies it as the recommended database for Drupal 10, 11, and 12. …<br />
Continue reading \"Drupal recommends MariaDB\"<br />
The post Drupal recommends MariaDB appeared first on MariaDB.org.</p>
<p>The post <a rel="nofollow" href="https://mariadb.org/drupal-recommends-mariadb/">Drupal recommends MariaDB</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>MariaDB is now clearly listed as the recommended database in Drupal&rsquo;s official documentation. Following <a href="https://www.drupal.org/project/drupal/issues/3478097">community discussion on </a><a href="http://drupal.org">Drupal.org</a>, the <a href="https://www.drupal.org/docs/getting-started/system-requirements/database-server-requirements">Database server requirements</a> now lists MariaDB first, and identifies it as the recommended database for Drupal 10, 11, and 12. &hellip; </p>
<p class="link-more"><a href="https://mariadb.org/drupal-recommends-mariadb/" class="more-link">Continue reading<span class="screen-reader-text"> &ldquo;Drupal recommends MariaDB&rdquo;</span></a></p>
<p>The post <a rel="nofollow" href="https://mariadb.org/drupal-recommends-mariadb/">Drupal recommends MariaDB</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>

<p>The post <a rel="nofollow" href="https://mariadb.org/drupal-recommends-mariadb/">Drupal recommends MariaDB</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Running TidesDB as a MySQL 9.7 storage engine</title>
      <link>https://www.percona.com/blog/running-tidesdb-as-a-mysql-9-7-storage-engine/</link>
      <pubDate>Mon, 25 May 2026 10:51:55 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://www.percona.com/blog/">Blog - Percona</source>
      <description><![CDATA[<p>tidesdb-mysql is an experimental build that was developed to verify how TidesDB, the LSM-tree key/value engine, can work with MySQL 9.7 as a storage engine. The current build is v0.2.4, and it’s an experiment, not a finished product. So you can use it in your tests if you also want to try TidesDB with MySQL … Continued<br />
The post Running TidesDB as a MySQL 9.7 storage engine appeared first on Percona.</p>
<p>The post <a rel="nofollow" href="https://www.percona.com/blog/running-tidesdb-as-a-mysql-9-7-storage-engine/">Running TidesDB as a MySQL 9.7 storage engine</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p><span style="font-weight: 400">tidesdb-mysql is an experimental build that was developed to verify how TidesDB, the LSM-tree key/value engine, can work with MySQL 9.7 as a storage engine. The current build is v0.2.4, </span><span style="font-weight: 400">and it&rsquo;s an experiment, not a finished product. So you can use it in your tests if you also want to try TidesDB with MySQL and compare with MariaDB</span></p>
<h2><b>Why we made it</b><a class="anchor-link" id="why-we-made-it"></a></h2>
<p><span style="font-weight: 400">There was already a way to use TidesDB from SQL. It&rsquo;s TideSQL, which loads the engine into MariaDB as </span><span style="font-weight: 400">ha_tidesdb</span><span style="font-weight: 400">, and it works fine. But it doesn&rsquo;t work with MySQL. So we wanted TidesDB to work with</span><span style="font-weight: 400"> MySQL 9.7.</span></p>
<p><span style="font-weight: 400">MariaDB and MySQL share a lot of history, but they are not the same. We couldn&rsquo;t just recompile the MariaDB plugin against MySQL headers and call it done. The one thing that stayed put through all of it was TidesDB itself, doing exactly what it does anywhere else. Only the server wrapped around was changed. In result we got our implementation, so if you&rsquo;re on MySQL, you no longer have to switch to MariaDB to give TidesDB a try.</span></p>
<h2><b>What it actually is</b><a class="anchor-link" id="what-it-actually-is"></a></h2>
<p><span style="font-weight: 400">tidesdb-mysql</span><span style="font-weight: 400"> is a loadable plugin, </span><span style="font-weight: 400">ha_tidesdb.so</span><span style="font-weight: 400">. The engine gets built on its own and loaded into the server at runtime, the same shape as the MariaDB version. It speaks the MySQL handler API and wires MySQL tables and indexes onto TidesDB column families. After it loads, </span><span style="font-weight: 400">TidesDB</span><span style="font-weight: 400"> sits right next to </span><span style="font-weight: 400">InnoDB</span><span style="font-weight: 400"> in </span><span style="font-weight: 400">SHOW ENGINES</span><span style="font-weight: 400"> and you choose it per table.</span></p>
<h2><b>Getting started</b><a class="anchor-link" id="getting-started"></a></h2>
<p><span style="font-weight: 400">All you need is Docker. Pull the image and start it:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">docker pull perconalab/tidesdb-mysql:0.2.4

docker run -d --name tidesdb 
-e MYSQL_ROOT_PASSWORD=secret 
-p 3306:3306 
perconalab/tidesdb-mysql:0.2.4</pre>
<p><span style="font-weight: 400">The plugin is baked into this image and loaded on boot, so there&rsquo;s no </span><span style="font-weight: 400">INSTALL PLUGIN</span><span style="font-weight: 400"> step to remember. Confirm the engine is live:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">docker exec tidesdb mysql -uroot -psecret 
-e "SELECT engine, support FROM information_schema.engines WHERE engine='TidesDB';"
# TidesDB | YES</pre>
<p>&nbsp;</p>
<p><span style="font-weight: 400">Now make a table and treat it like any other:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">CREATE DATABASE shop;
USE shop;

CREATE TABLE products (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(64) NOT NULL,
price DECIMAL(10,2) NOT NULL,
KEY idx_price (price)
) ENGINE=TIDESDB;

INSERT INTO products (name, price) VALUES ('Widget', 9.99), ('Gadget', 24.50);
SELECT * FROM products WHERE price &lt; 20;</pre>
<p>&nbsp;</p>
<p><span style="font-weight: 400">Transactions, secondary indexes, the usual SQL, it all behaves:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">START TRANSACTION;
UPDATE products SET price = price + 1 WHERE name = 'Widget';
COMMIT;</pre>
<p>&nbsp;</p>
<p><span style="font-weight: 400">Per-table TidesDB options ride along in MySQL&rsquo;s </span><span style="font-weight: 400">ENGINE_ATTRIBUTE</span><span style="font-weight: 400"> JSON field. MySQL doesn&rsquo;t have MariaDB&rsquo;s </span><span style="font-weight: 400">COMPRESSION=&hellip;</span><span style="font-weight: 400"> grammar, so the options are identical but you write them differently:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">CREATE TABLE events (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
msg TEXT
) ENGINE=TIDESDB
ENGINE_ATTRIBUTE='{"compression":"ZSTD","bloom_filter":true}';</pre>
<p><span style="font-weight: 400">Compression accepts </span><span style="font-weight: 400">NONE</span><span style="font-weight: 400">, </span><span style="font-weight: 400">SNAPPY</span><span style="font-weight: 400">, </span><span style="font-weight: 400">LZ4</span><span style="font-weight: 400">, </span><span style="font-weight: 400">ZSTD</span><span style="font-weight: 400">, or </span><span style="font-weight: 400">LZ4_FAST</span><span style="font-weight: 400">. Server-wide knobs live in system variables such as </span><span style="font-weight: 400">tidesdb_default_compression</span><span style="font-weight: 400">, </span><span style="font-weight: 400">tidesdb_block_cache_size</span><span style="font-weight: 400">, </span><span style="font-weight: 400">tidesdb_compaction_threads</span><span style="font-weight: 400">, and </span><span style="font-weight: 400">tidesdb_flush_threads</span><span style="font-weight: 400">. The full list is in </span><span style="font-weight: 400">docs/build-and-load.md</span><span style="font-weight: 400">.</span></p>
<h2><b>Prove the crash recovery</b><a class="anchor-link" id="prove-the-crash-recovery"></a></h2>
<p><span style="font-weight: 400">Write a handful of rows, kill the server with no clean shutdown, bring it back, and count what&rsquo;s left:</span></p>
<p><i><span style="font-weight: 400"># 1. Write rows inside a transaction and COMMIT.</span></i><i><span style="font-weight: 400"><br>
</span></i></p>
<pre class="urvanov-syntax-highlighter-plain-tag">docker exec -i tidesdb mysql -uroot -psecret &lt;&lt;'SQL'
CREATE DATABASE IF NOT EXISTS t;
CREATE TABLE IF NOT EXISTS t.kv (k INT PRIMARY KEY, v VARCHAR(32)) ENGINE=TIDESDB;
BEGIN;
INSERT INTO t.kv VALUES (1,'a'),(2,'b'),(3,'c'),(4,'d'),(5,'e');
COMMIT;
SELECT COUNT(*) AS before_crash FROM t.kv; -- 5
SQL</pre>
<p><span style="font-weight: 400"><br>
</span> <i><span style="font-weight: 400"># 2. Hard-kill the server (no graceful shutdown) and restart it.</span></i><i><span style="font-weight: 400"><br>
</span></i><b></b></p>
<pre class="urvanov-syntax-highlighter-plain-tag">docker kill -s KILL tidesdb
docker start tidesdb
until docker exec tidesdb mysql -uroot -psecret -e 'SELECT 1' &gt;/dev/null 2&gt;&amp;1; do sleep 2; done</pre>
<p><b></b><i><span style="font-weight: 400"># 3. The committed rows are still there.</span></i><i><span style="font-weight: 400"><br>
</span></i></p>
<pre class="urvanov-syntax-highlighter-plain-tag">docker exec tidesdb mysql -uroot -psecret 
-e "SELECT COUNT(*) AS after_crash FROM t.kv;" -- 5</pre>
<p><span style="font-weight: 400">after_crash</span><span style="font-weight: 400"> should come back equal to </span><span style="font-weight: 400">before_crash</span><span style="font-weight: 400">.</span></p>
<h2><b>A few more things to try</b><a class="anchor-link" id="a-few-more-things-to-try"></a></h2>
<p><span style="font-weight: 400">Compression is the one people ask about first, so here&rsquo;s a table that leans on it. We generate a couple thousand rows of repetitive text, which is exactly the shape ZSTD likes:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">CREATE TABLE logs (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
level VARCHAR(8) NOT NULL,
body TEXT,
KEY idx_level (level)
) ENGINE=TIDESDB
ENGINE_ATTRIBUTE='{"compression":"ZSTD","bloom_filter":true}';</pre>

<pre class="urvanov-syntax-highlighter-plain-tag">INSERT INTO logs (level, body)
SELECT IF(RAND() &lt; 0.2, 'warn', 'info'),
REPEAT('the quick brown fox jumps over the lazy dog ', 40)
FROM information_schema.columns
LIMIT 2000;</pre>

<pre class="urvanov-syntax-highlighter-plain-tag">SELECT level, COUNT(*) AS rows FROM logs GROUP BY level;
SELECT id, LEFT(body, 30) AS preview FROM logs WHERE id = 1000;</pre>
<p><span style="font-weight: 400">The rows go in compressed and come back out as the original text, so queries don&rsquo;t change at all. If you want to confirm the option actually landed on the table rather than being silently dropped, ask the server what it stored:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">SHOW CREATE TABLE logsG
-- ENGINE=TIDESDB ... ENGINE_ATTRIBUTE='{"compression":"ZSTD","bloom_filter":true}'</pre>
<p><span style="font-weight: 400">The bloom filter from that same attribute is what keeps point lookups cheap once the data has compacted down into several on-disk files:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">SELECT id, level FROM logs WHERE id = 1500;</pre>
<p><span style="font-weight: 400">A JSON column behaves the way you&rsquo;d expect, including the </span><span style="font-weight: 400">-&gt;&gt;</span><span style="font-weight: 400"> extraction operator:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">CREATE TABLE kv (k VARCHAR(64) PRIMARY KEY, v JSON) ENGINE=TIDESDB;

INSERT INTO kv VALUES
('en', JSON_OBJECT('lang','English', 'msg','hello')),
('es', JSON_OBJECT('lang','Spanish', 'msg','hola')),
('fr', JSON_OBJECT('lang','French', 'msg','bonjour'));

SELECT k, v-&gt;&gt;'$.lang' AS language, v-&gt;&gt;'$.msg' AS greeting
FROM kv
ORDER BY k;</pre>
<p><span style="font-weight: 400">And the secondary index on </span><span style="font-weight: 400">products</span><span style="font-weight: 400"> from earlier is a real index, not decoration. A range query uses it, and </span><span style="font-weight: 400">EXPLAIN</span><span style="font-weight: 400"> will show </span><span style="font-weight: 400">idx_price</span><span style="font-weight: 400"> in the </span><span style="font-weight: 400">key</span><span style="font-weight: 400"> column:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">SELECT name, price FROM products WHERE price BETWEEN 5 AND 20 ORDER BY price;

EXPLAIN SELECT name, price FROM products WHERE price BETWEEN 5 AND 20;</pre>

<h2><b>What works, and what doesn&rsquo;t yet</b><a class="anchor-link" id="what-works-and-what-doesnt-yet"></a></h2>
<p><span style="font-weight: 400">Quite a bit works. The common column types are all there, primary keys single and composite, </span><span style="font-weight: 400">AUTO_INCREMENT</span><span style="font-weight: 400">, secondary indexes with index-condition pushdown, </span><span style="font-weight: 400">COMMIT</span><span style="font-weight: 400">/</span><span style="font-weight: 400">ROLLBACK</span><span style="font-weight: 400">, </span><span style="font-weight: 400">REPLACE</span><span style="font-weight: 400"> and </span><span style="font-weight: 400">INSERT &hellip; ON DUPLICATE KEY UPDATE</span><span style="font-weight: 400">, online add/drop index, instant add column, full-text search, spatial indexes, per-row TTL, per-table compression and bloom filters, at-rest encryption, and mixed-engine transactions where a TidesDB table and an InnoDB table share one </span><span style="font-weight: 400">BEGIN &hellip; COMMIT</span><span style="font-weight: 400">. The functional test suite, which we lifted from TideSQL and then extended, passes 58 of 58 executed tests.</span></p>
<p><span style="font-weight: 400">A few things you should know about before you lean on it:</span></p>
<ul>
<li style="font-weight: 400"><span style="font-weight: 400">Native </span> <span style="font-weight: 400">partitioning and the MySQL 9 vector column type aren&rsquo;t implemented. </span> <span style="font-weight: 400">Those two test cases are skipped deliberately.</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Atomic, </span> <span style="font-weight: 400">crash-safe DDL (the data-dictionary integration) is wired up but we </span> <span style="font-weight: 400">haven&rsquo;t driven it end-to-end yet. Your data writes are crash-safe; </span> <span style="font-weight: 400">schema changes during a crash are next on the list.</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Replication, </span> <span style="font-weight: 400">foreign keys, and nested savepoints aren&rsquo;t in scope at the moment.</span></li>
</ul>
<p><span style="font-weight: 400">Treat v0.2.5 as a serious experiment. It&rsquo;s solid enough that committed data rides through a crash, and it&rsquo;s not something we&rsquo;d point production traffic at yet.</span></p>
<h2><b>Try it, then tell us</b><a class="anchor-link" id="try-it-then-tell-us"></a></h2>

<pre class="urvanov-syntax-highlighter-plain-tag">docker pull perconalab/tidesdb-mysql:0.2.5</pre>
<p><span style="font-weight: 400">That&rsquo;s the whole setup. Spin up a table with </span><span style="font-weight: 400">ENGINE=TIDESDB</span><span style="font-weight: 400">, run the crash demo, and point your own SQL at it. The source, the build scripts, and the engine patches all live in the</span><a href="https://github.com/EvgeniyPatlan/tidesdb-mysql"> <span style="font-weight: 400">tidesdb-mysql</span></a><span style="font-weight: 400"> repository, and the durability fixes are written up in </span><span style="font-weight: 400">KNOWN-ISSUES.md</span><span style="font-weight: 400">. This is a tool made by users for users, so if you give it a spin, we&rsquo;d genuinely like to hear what held up and what fell over.</span></p>
<p>The post <a href="https://www.percona.com/blog/running-tidesdb-as-a-mysql-9-7-storage-engine/">Running TidesDB as a MySQL 9.7 storage engine</a> appeared first on <a href="https://www.percona.com">Percona</a>.</p>

<p>The post <a rel="nofollow" href="https://www.percona.com/blog/running-tidesdb-as-a-mysql-9-7-storage-engine/">Running TidesDB as a MySQL 9.7 storage engine</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Migrate from Crunchy Data PostgreSQL Operator to Percona PostgreSQL Operator: Standby Cluster Method</title>
      <link>https://www.percona.com/blog/migrate-from-crunchy-data-to-percona-postgresql-operator-standby-cluster/</link>
      <pubDate>Mon, 25 May 2026 07:49:01 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://www.percona.com/blog/">Blog - Percona</source>
      <description><![CDATA[<p>A Crunchy to Percona PostgreSQL migration is more straightforward than most cross-operator moves on Kubernetes, because the Percona PostgreSQL Operator is a hard fork of the Crunchy Data PostgreSQL Operator. Same Patroni HA, same pgBackRest backups, same overall CRD shape. This post walks through the safest of the three migration paths: a standby cluster method … Continued<br />
The post Migrate from Crunchy Data PostgreSQL Operator to Percona PostgreSQL Operator: Standby Cluster Method appeared first on Percona.</p>
<p>The post <a rel="nofollow" href="https://www.percona.com/blog/migrate-from-crunchy-data-to-percona-postgresql-operator-standby-cluster/">Migrate from Crunchy Data PostgreSQL Operator to Percona PostgreSQL Operator: Standby Cluster Method</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p><img decoding="async" loading="lazy" class="aligncenter wp-image-47080 size-large" src="https://www.percona.com/wp-content/uploads/2026/05/hero-1024x375.png" alt="" width="1024" height="375"></p>
<p>A Crunchy to Percona PostgreSQL migration is more straightforward than most cross-operator moves on Kubernetes, because the Percona PostgreSQL Operator is a hard fork of the Crunchy Data PostgreSQL Operator. Same Patroni HA, same pgBackRest backups, same overall CRD shape. This post walks through the safest of the three migration paths: a standby cluster method with near-zero downtime.</p>
<p><span style="font-weight: 400">This is </span><b><strong>part 2</strong> </b><span style="font-weight: 400">of a </span><b><strong>3-part </strong></b><span style="font-weight: 400">series on running PostgreSQL on Kubernetes with a fully open-source operator. </span><a href="https://www.percona.com/blog/not-all-open-source-is-equal-choosing-postgresql-operator-kubernetes-2026/"><span style="font-weight: 400">Part 1</span></a><span style="font-weight: 400"> walked through the changing open-source landscape and announced the hard fork of the Crunchy Data PostgreSQL Operator into the fully independent <a href="https://github.com/percona/percona-postgresql-operator/tree/v3.0.0"><strong>Percona PostgreSQL Operator v3.0.0</strong></a>.</span></p>
<p><span style="font-weight: 400">This post is the first practical playbook of the series. It covers the </span><b><strong>standby cluster method</strong>, </b><span style="font-weight: 400">the safest migration path when the downtime budget is tight. <strong>Part 3</strong> will cover two simpler paths: backup-and-restore and persistent-volume reuse.</span></p>
<p><span style="font-weight: 400">If you are landing here without context on why you might want to migrate at all, </span><a href="https://www.percona.com/blog/not-all-open-source-is-equal-choosing-postgresql-operator-kubernetes-2026/"><span style="font-weight: 400">start with part 1</span></a><span style="font-weight: 400">. The rest of this post assumes you have already decided to move and want a tested playbook.</span></p>
<p>&nbsp;</p>
<h2><b>Migration approach in one paragraph</b><a class="anchor-link" id="migration-approach-in-one-paragraph"></a></h2>
<p><span style="font-weight: 400">The <strong>Percona PostgreSQL Kubernetes Operator</strong> is a hard fork of the Crunchy Data PostgreSQL Kubernetes Operator, which simplifies the migration paths considerably: the same underlying tools (<strong>Patroni</strong>, <strong>pgBackRest</strong>, <strong>PgBouncer</strong>) and the same overall design are used in both operators. All three migration paths in this series are reversible: because Percona&rsquo;s operator is fully open source and remains compatible with the same backup format, the move back to Crunchy is also possible if your team decides to walk it</span></p>
<p>&nbsp;</p>
<h3><b>A note on the storage layer</b><a class="anchor-link" id="a-note-on-the-storage-layer"></a></h3>
<p><span style="font-weight: 400">All examples in this guide use an in-cluster <a href="https://github.com/seaweedfs/seaweedfs">SeaweedFS</a> instance as the <strong>pgBackRest</strong> S3 repository. <strong>SeaweedFS</strong> is Apache-2.0 licensed, actively maintained, and a clean drop-in replacement for the role <strong>MinIO</strong> used to fill in this stack. Any other S3-compatible storage works just as well: AWS S3, Google Cloud Storage (via HMAC keys), Ceph RadosGW, Cloudflare R2, and so on. For non-<strong>SeaweedFS</strong> endpoints, remove <em>repo1-s3-uri-style: path</em>&nbsp;and <em>repo1-s3-verify-tls: &ldquo;n&rdquo;</em> from the pgBackRest configuration and replace the endpoint with your provider&rsquo;s URL.</span></p>
<p>&nbsp;</p>
<h3><b>What this series does NOT cover</b><a class="anchor-link" id="what-this-series-does-not-cover"></a></h3>
<p><span style="font-weight: 400">To keep scope honest:</span></p>
<ul>
<li style="font-weight: 400"><span style="font-weight: 400">Application-side connection-string changes beyond updating to the new pgBouncer service. If your app uses connection-pool tuning, custom auth, or a service mesh, that work stays with you.</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Schema-changing upgrades, major PostgreSQL version upgrades, or extension migrations. The PostgreSQL major version must match between the source and the target.</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Crunchy enterprise-only features like TDE, Crunchy Postgres for Kubernetes-specific operators, or pgBackRest custom encryption. If your environment uses these, contact the Percona team for a tailored plan.</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Operating two operators against the same namespace before the PGO hard fork. Use Percona PostgreSQL Operator v3.0.0 or higher.</span></li>
</ul>
<p>&nbsp;</p>
<h3><b>Tested with</b><a class="anchor-link" id="tested-with"></a></h3>
<table>
<tbody>
<tr>
<td><b>Component</b></td>
<td><b>Version</b></td>
</tr>
<tr>
<td><span style="font-weight: 400">Crunchy Data PostgreSQL Kubernetes Operator</span></td>
<td><span style="font-weight: 400">v5.8.x (tested on v5.8.7)</span></td>
</tr>
<tr>
<td><a href="https://docs.percona.com/percona-operator-for-postgresql/latest/"><span style="font-weight: 400">Percona PostgreSQL Kubernetes Operator</span></a></td>
<td>v3.x.x (tested on v3.0.0)</td>
</tr>
<tr>
<td><span style="font-weight: 400">PostgreSQL</span></td>
<td><span style="font-weight: 400">18 (must match between source and target)</span></td>
</tr>
<tr>
<td><span style="font-weight: 400">Object storage</span></td>
<td><span style="font-weight: 400">SeaweedFS (Apache-2.0), or any other S3-compatible service accessible from all cluster pods</span></td>
</tr>
<tr>
<td><span style="font-weight: 400">Tools</span></td>
<td><span style="font-weight: 400">kubectl</span><span style="font-weight: 400">, </span><span style="font-weight: 400">helm</span> <span style="font-weight: 400">(v3)</span><span style="font-weight: 400">, </span><span style="font-weight: 400">yq</span></td>
</tr>
</tbody>
</table>
<p><span style="font-weight: 400">Different versions may differ slightly in CR fields or behavior. Always consult the official documentation for the operator and PostgreSQL version you are running.</span></p>
<p>&nbsp;</p>
<h2><b>Migration using a standby cluster</b><a class="anchor-link" id="migration-using-a-standby-cluster"></a></h2>
<p><span style="font-weight: 400">This is the safest method when the downtime budget is tight. The Percona cluster is brought up as a standby of the Crunchy primary, catches up via pgBackRest plus streaming replication, and is promoted at cutover. The only downtime is the cutover step itself.</span></p>
<p><span style="font-weight: 400">You can wire the standby in two ways, and combining both gives you maximum safety:</span></p>
<ul>
<li style="font-weight: 400"><b>pgBackRest repo-based standby</b><span style="font-weight: 400"> seeds the standby from the latest base backup and replays archived WAL</span></li>
<li style="font-weight: 400"><b>Streaming replication </b><span style="font-weight: 400">keeps the standby in sync with the live primary</span></li>
</ul>
<p>&nbsp;</p>
<h3><b>Overview</b><a class="anchor-link" id="overview"></a></h3>
<p><span style="font-weight: 400"><br>
</span><img decoding="async" loading="lazy" class="aligncenter wp-image-47083 size-large" src="https://www.percona.com/wp-content/uploads/2026/05/standby-1024x393.png" alt="" width="1024" height="393"></p>
<p>&nbsp;</p>
<h3><b>Before you begin</b><a class="anchor-link" id="before-you-begin"></a></h3>
<p><span style="font-weight: 400">Set the target namespace once. Every command in this guide reads from this variable, so you can change it in a single place:<br>
</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">export MIGRATION_NS=postgres-migration
kubectl create namespace $MIGRATION_NS</pre>
<p>&nbsp;</p>
<h3><b>Deploy SeaweedFS</b><a class="anchor-link" id="deploy-seaweedfs"></a></h3>
<p><span style="font-weight: 400">Skip this step if you already have an S3-compatible repository (AWS S3, GCS, Ceph). Update the endpoint and credentials in the YAML examples accordingly.</span></p>
<p><span style="font-weight: 400"><strong>SeaweedFS</strong> provides an S3-compatible object store that runs inside Kubernetes. Both operators will use it as the shared pgBackRest WAL archive.</span></p>
<p><b>TLS is required. </b><span style="font-weight: 400"><strong>pgBackRest</strong> always connects to S3 endpoints over HTTPS, even when </span><em><span style="font-weight: 400">repo1-s3-verify-tls: &ldquo;n&rdquo;</span></em><span style="font-weight: 400"> is set (that flag skips certificate verification, it does not fall back to HTTP). The steps below generate a self-signed certificate and pass it to <strong>SeaweedFS</strong> via <strong>Helm</strong> values.<br>
</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag"># Generate a self-signed TLS certificate for SeaweedFS S3
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 
  -keyout /tmp/seaweedfs.key 
  -out /tmp/seaweedfs.crt 
  -subj "/CN=seaweedfs-all-in-one"

kubectl -n $MIGRATION_NS create secret tls seaweedfs-s3-tls 
  --cert=/tmp/seaweedfs.crt 
  --key=/tmp/seaweedfs.key

helm repo add seaweedfs https://seaweedfs.github.io/seaweedfs/helm
helm repo update

helm install seaweedfs seaweedfs/seaweedfs 
  --namespace $MIGRATION_NS 
  --version 4.23.0 
  -f https://raw.githubusercontent.com/percona/percona-postgresql-operator/refs/heads/migration-from-crunchy-guide/e2e-tests/tests/migration-from-crunchy-standby/examples/seaweedfs-values.yaml 
  --wait</pre>
<p><span style="font-weight: 400">The Helm values file in the repo creates the </span><em><span style="font-weight: 400">pg-migration</span></em><span style="font-weight: 400"> bucket on first start, so no separate </span><em><span style="font-weight: 400">aws s3 mb</span></em><span style="font-weight: 400"> step is needed.</span></p>
<p>&nbsp;</p>
<h3><b>Step 0. Create pgBackRest secrets</b><a class="anchor-link" id="step-0-create-pgbackrest-secrets"></a></h3>
<p><span style="font-weight: 400">Both operators need credentials to read and write the shared <strong>SeaweedFS</strong> bucket. Apply the secrets from <a href="https://raw.githubusercontent.com/percona/percona-postgresql-operator/refs/heads/migration-from-crunchy-guide/e2e-tests/tests/migration-from-crunchy-standby/examples/01-pgbackrest-secret.yaml">examples/01-pgbackrest-secret.yaml</a> after filling in your access key and secret key:<br>
</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag"># Copy and edit the file first to set your credentials.

kubectl apply -n $MIGRATION_NS 
  -f https://raw.githubusercontent.com/percona/percona-postgresql-operator/refs/heads/migration-from-crunchy-guide/e2e-tests/tests/migration-from-crunchy-standby/examples/01-pgbackrest-secret.yaml</pre>
<p><span style="font-weight: 400">Both secrets contain the same <strong>SeaweedFS</strong> credentials (</span><em><span style="font-weight: 400">pgmigration</span></em><span style="font-weight: 400"> / </span><em><span style="font-weight: 400">pgmigration123</span></em><span style="font-weight: 400"><em>)</em>. For AWS S3, replace those with your IAM access key ID and secret access key.</span></p>
<p>&nbsp;</p>
<h3><b>Step 1. Start with your existing Crunchy Data cluster</b><a class="anchor-link" id="step-1-start-with-your-existing-crunchy-data-cluster"></a></h3>
<p><span style="font-weight: 400">If you already have a running Crunchy cluster, ensure its pgBackRest </span><em><span style="font-weight: 400">repo1</span></em><span style="font-weight: 400"> points at the shared bucket and path. The </span><em><span style="font-weight: 400">repo1-path</span></em><span style="font-weight: 400"> value must be identical in both cluster specs. Mismatched paths will prevent the Percona standby from finding the WAL archive.</span></p>
<p><strong>The Helm install below is shown only as a quick way to reproduce this blog post&rsquo;s example. The migration steps in the rest of this post do not depend on how you deployed the source operator.</strong></p>
<p><span style="font-weight: 400">Optional: deploy a Crunchy operator to test the migration end to end:<br>
</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">helm install pgo 
  oci://registry.developers.crunchydata.com/crunchydata/pgo 
  -n $MIGRATION_NS 
  --version 5.8.7 
  --set singleNamespace=true 
  --wait</pre>
<p><span style="font-weight: 400"><br>
Apply </span><a href="https://raw.githubusercontent.com/percona/percona-postgresql-operator/refs/heads/migration-from-crunchy-guide/e2e-tests/tests/migration-from-crunchy-standby/examples/02-crunchy-source-cluster.yaml"><span style="font-weight: 400">examples/02-crunchy-source-cluster.yaml</span></a><span style="font-weight: 400"> (or adapt your existing cluster&rsquo;s pgBackRest config):</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">kubectl apply -n $MIGRATION_NS 
  -f https://raw.githubusercontent.com/percona/percona-postgresql-operator/refs/heads/migration-from-crunchy-guide/e2e-tests/tests/migration-from-crunchy-standby/examples/02-crunchy-source-cluster.yaml</pre>
<p><span style="font-weight: 400"><br>
The key pgBackRest settings in the example:<br>
</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">global:
  repo1-path: /crunchy-to-percona/repo1   # shared path, must match Percona side
  repo1-s3-uri-style: path                # required for path-style S3 endpoints (SeaweedFS, MinIO)
  repo1-s3-verify-tls: "n"                # skip TLS verification for self-signed cert; remove for AWS S3
repos:
  - name: repo1
    s3:
      bucket: pg-migration
      endpoint: seaweedfs-all-in-one.postgres-migration.svc.cluster.local:8443
      region: us-east-1</pre>
<p><span style="font-weight: 400"><br>
<span style="font-weight: 400">Wait for the cluster to be ready:</span></span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">kubectl wait pod 
  --selector postgres-operator.crunchydata.com/cluster=crunchy-source,postgres-operator.crunchydata.com/data=postgres 
  --namespace $MIGRATION_NS 
  --for=condition=Ready 
  --timeout=300s</pre>
<p>&nbsp;</p>
<h3><b><br>
Step 2. Trigger a full backup on the Crunchy cluster</b><a class="anchor-link" id="step-2-trigger-a-full-backup-on-the-crunchy-cluster"></a></h3>
<p><span style="font-weight: 400">Wait for the pgBackRest stanza to be created:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">kubectl wait postgrescluster/crunchy-source 
  -n $MIGRATION_NS 
  --for=jsonpath='{.status.pgbackrest.repos[0].stanzaCreated}'=true 
  --timeout=300s</pre>
<p><span style="font-weight: 400">Take a full backup before creating the Percona standby. This gives the standby a recent base to restore from, so it only needs to replay a small amount of WAL to catch up. This matches the realistic production migration pattern.</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">kubectl annotate postgrescluster crunchy-source 
  --namespace $MIGRATION_NS 
  postgres-operator.crunchydata.com/pgbackrest-backup="$(date +%s)"</pre>
<p><span style="font-weight: 400"><br>
Wait for the backup job to complete:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">kubectl wait job 
  -l postgres-operator.crunchydata.com/pgbackrest-backup=manual,postgres-operator.crunchydata.com/cluster=crunchy-source 
  -n $MIGRATION_NS 
  --for=condition=Complete 
  --timeout=600s</pre>
<p>&nbsp;</p>
<h3><b><br>
Step 3. Copy TLS certificates (cross-namespace only)</b><a class="anchor-link" id="step-3-copy-tls-certificates-cross-namespace-only"></a></h3>
<p><span style="font-weight: 400">If the Percona cluster is in a different namespace from the Crunchy cluster, copy the Crunchy TLS secrets to the Percona namespace. These allow mutual TLS authentication during streaming replication:<br>
</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">for secret in crunchy-source-cluster-cert crunchy-source-replication-cert; do
  kubectl get secret "${secret}" -n &lt;CRUNCHY_NS&gt; -o json | 
    yq '{"apiVersion": .apiVersion, "kind": .kind, "data": .data,
         "metadata": {"name": .metadata.name}, "type": .type}' -o yaml | 
    kubectl -n $MIGRATION_NS apply -f -
done</pre>
<p><span style="font-weight: 400">If both clusters are in the same namespace, skip this step. The secrets are already accessible.</span></p>
<p>&nbsp;</p>
<h3><b>Step 4. Deploy the Percona PG Operator</b><a class="anchor-link" id="step-4-deploy-the-percona-pg-operator"></a></h3>
<p><span style="font-weight: 400">The Crunchy PGO operator can stay in the same or a different namespace.<br>
</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">kubectl apply -n $MIGRATION_NS --server-side 
  -f https://raw.githubusercontent.com/percona/percona-postgresql-operator/refs/tags/v3.0.0/deploy/bundle.yaml</pre>
<p><span style="font-weight: 400">Wait until the operator deployment is ready:<br>
</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">kubectl wait deployment percona-postgresql-operator 
  -n $MIGRATION_NS 
  --for=condition=Available 
  --timeout=120s</pre>
<p>&nbsp;</p>
<h3><b>Step 5. Create the Percona cluster in standby mode</b><a class="anchor-link" id="step-5-create-the-percona-cluster-in-standby-mode"></a></h3>
<p><strong>Note</strong>: The&nbsp;<code>kubectl apply</code> below pulls the CR manifest from the <code>migration-from-crunchy-guide</code>&nbsp;branch of the operator repo, which is the source for this guide&rsquo;s examples. For production deployments, follow&nbsp;<a href="https://docs.percona.com/percona-operator-for-postgresql/latest/kubectl.html" rel="nofollow">the official Percona Operator for PostgreSQL installation documentation</a>&nbsp;and pin to a released version tag rather than a feature branch.</p>
<p><span style="font-weight: 400">Apply </span><a href="https://raw.githubusercontent.com/percona/percona-postgresql-operator/refs/heads/migration-from-crunchy-guide/e2e-tests/tests/migration-from-crunchy-standby/examples/03-percona-standby-cluster.yaml"><span style="font-weight: 400">examples/03-percona-standby-cluster.yaml</span></a><span style="font-weight: 400">:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">kubectl apply -n $MIGRATION_NS 
  -f https://raw.githubusercontent.com/percona/percona-postgresql-operator/refs/heads/migration-from-crunchy-guide/e2e-tests/tests/migration-from-crunchy-standby/examples/03-percona-standby-cluster.yaml</pre>
<p><span style="font-weight: 400">The key settings that wire the Percona cluster to the Crunchy source:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">standby:
  enabled: true
  repoName: repo1                             # restore initial base backup from this repo
  host: crunchy-source-ha.postgres-migration.svc.cluster.local
  port: 5432

secrets:
  customTLSSecret:
    name: crunchy-source-cluster-cert         # Crunchy CA for mutual TLS
  customReplicationTLSSecret:
    name: crunchy-source-replication-cert     # cert for _crunchyreplication user</pre>
<p><span style="font-weight: 400">The Percona operator will:</span></p>
<ol>
<li style="font-weight: 400"><span style="font-weight: 400">Restore the base backup from the <strong>SeaweedFS</strong> bucket.</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Replay WAL from <strong>SeaweedFS</strong> until it catches up with the live Crunchy cluster.</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Switch to streaming replication from </span><em><span style="font-weight: 400">crunchy-source-ha</span><span style="font-weight: 400">.</span></em></li>
</ol>
<p><span style="font-weight: 400">Wait for the cluster to reach the ready state:<br>
</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">kubectl wait perconapgcluster/percona-standby 
  -n $MIGRATION_NS 
  --for=jsonpath='{.status.state}'=ready 
  --timeout=600s</pre>
<p><span style="font-weight: 400">Verify that data is replicating to the standby:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">STANDBY_POD=$(kubectl get pod -n $MIGRATION_NS 
  -l postgres-operator.crunchydata.com/cluster=percona-standby,postgres-operator.crunchydata.com/data=postgres 
  -o jsonpath='{.items[0].metadata.name}')

kubectl -n $MIGRATION_NS exec "${STANDBY_POD}" -c database -- 
  psql -t -c "SELECT pg_is_in_recovery(), pg_last_wal_replay_lsn();"</pre>
<p><span style="font-weight: 400">Expected output: </span><span style="font-weight: 400">t</span><span style="font-weight: 400"> (in recovery) and a non-null LSN.</span><span style="font-weight: 400"><br>
</span><span style="font-weight: 400"><br>
</span></p>
<p>&nbsp;</p>
<h3><b>Step 6. Verify replication lag before cutover</b><a class="anchor-link" id="step-6-verify-replication-lag-before-cutover"></a></h3>
<p><span style="font-weight: 400">Query the Crunchy primary to confirm the Percona standby has caught up:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">CRUNCHY_PRIMARY=$(kubectl get pod 
  -l postgres-operator.crunchydata.com/cluster=crunchy-source,postgres-operator.crunchydata.com/role=master 
  -n $MIGRATION_NS 
  -o jsonpath='{.items[0].metadata.name}')

kubectl -n $MIGRATION_NS exec "${CRUNCHY_PRIMARY}" -c database -- 
  psql -c "
    SELECT
        client_addr,
        state,
        pg_wal_lsn_diff(sent_lsn, replay_lsn) AS byte_lag,
        write_lag,
        flush_lag,
        replay_lag
    FROM pg_stat_replication;
  "</pre>
<p><span style="font-weight: 400">Proceed to the next step only when </span><em><span style="font-weight: 400">write_lag</span></em><span style="font-weight: 400"> and </span><em><span style="font-weight: 400">replay_lag</span></em><span style="font-weight: 400"> are <em>NULL</em> or under a few seconds.</span></p>
<p>&nbsp;</p>
<h3><b>Step 7. Cutover the Crunchy cluster</b><a class="anchor-link" id="step-7-cutover-the-crunchy-cluster"></a></h3>
<p><span style="font-weight: 400">This is the only step that causes downtime. Stop accepting writes on the application side, then patch the Crunchy cluster into standby mode. Patroni steps down and archives the final WAL.</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">kubectl patch postgrescluster crunchy-source 
  -n $MIGRATION_NS 
  --type=merge 
  -p '{"spec": {"standby": {"enabled": true, "repoName": "repo1"}}}'</pre>
<p><span style="font-weight: 400">Verify demotion (poll until <em>pg_is_in_recovery()</em> returns <em>t</em>):</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">kubectl -n $MIGRATION_NS exec "${CRUNCHY_PRIMARY}" -c database -- 
  psql -t -c "SELECT pg_is_in_recovery();"</pre>
<p>&nbsp;</p>
<h3><b>Step 8. (Optional) Shut down the Crunchy cluster</b><a class="anchor-link" id="step-8-optional-shut-down-the-crunchy-cluster"></a></h3>
<p><span style="font-weight: 400">Once the Percona standby has replayed all WAL, shut down the Crunchy cluster to prevent split-brain:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">kubectl patch postgrescluster crunchy-source 
  -n $MIGRATION_NS 
  --type=merge 
  -p '{"spec": {"shutdown": true}}'

kubectl wait pod 
  -l postgres-operator.crunchydata.com/cluster=crunchy-source,postgres-operator.crunchydata.com/data=postgres 
  -n $MIGRATION_NS 
  --for=delete 
  --timeout=120s || true</pre>
<p>&nbsp;</p>
<h3><b>Step 9. Promote the Percona cluster</b><a class="anchor-link" id="step-9-promote-the-percona-cluster"></a></h3>
<p><span style="font-weight: 400">Confirm that the Percona standby has finished replaying all WAL (the LSN stops advancing):</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">kubectl -n $MIGRATION_NS exec "${STANDBY_POD}" -c database -- 
  psql -t -c "SELECT pg_last_wal_replay_lsn();"</pre>
<p><span style="font-weight: 400">Run this a few times. When the LSN is stable, replay is complete.</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">kubectl patch perconapgcluster percona-standby 
  -n $MIGRATION_NS 
  --type=merge 
  -p '{"spec": {"standby": {"enabled": false}}}'</pre>
<p><span style="font-weight: 400">Wait for the cluster to become ready and confirm it is writable:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">kubectl wait perconapgcluster/percona-standby 
  -n $MIGRATION_NS 
  --for=jsonpath='{.status.state}'=ready 
  --timeout=480s

PERCONA_PRIMARY=$(kubectl get pod -n $MIGRATION_NS 
  -l postgres-operator.crunchydata.com/cluster=percona-standby,postgres-operator.crunchydata.com/role=primary 
  -o jsonpath='{.items[0].metadata.name}')

kubectl -n $MIGRATION_NS exec "${PERCONA_PRIMARY}" -c database -- 
  psql -t -c "SELECT pg_is_in_recovery();"</pre>
<p><span style="font-weight: 400">Expected output: </span><em><span style="font-weight: 400">f</span></em><span style="font-weight: 400"> (the cluster is now the primary and accepts writes).</span></p>
<p>&nbsp;</p>
<h3><b>Step 10. Verify stanza creation</b><a class="anchor-link" id="step-10-verify-stanza-creation"></a></h3>

<pre class="urvanov-syntax-highlighter-plain-tag">kubectl wait perconapgcluster/percona-standby 
  -n $MIGRATION_NS 
  --for=jsonpath='{.status.pgbackrest.repos[0].stanzaCreated}'=true 
  --timeout=300s</pre>
<p>&nbsp;</p>
<h3><b>Step 11. Take a post-migration backup</b><a class="anchor-link" id="step-11-take-a-post-migration-backup"></a></h3>
<p><span style="font-weight: 400">Apply </span><a href="https://raw.githubusercontent.com/percona/percona-postgresql-operator/refs/heads/migration-from-crunchy-guide/e2e-tests/tests/migration-from-crunchy-standby/examples/04-post-migration-backup.yaml"><span style="font-weight: 400">examples/04-post-migration-backup.yaml</span></a><span style="font-weight: 400">:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">kubectl apply -n $MIGRATION_NS 
  -f https://raw.githubusercontent.com/percona/percona-postgresql-operator/refs/heads/migration-from-crunchy-guide/e2e-tests/tests/migration-from-crunchy-standby/examples/04-post-migration-backup.yaml

kubectl wait perconapgbackup/post-migration-backup 
  -n $MIGRATION_NS 
  --for=jsonpath='{.status.state}'=Succeeded 
  --timeout=600s</pre>
<p><span style="font-weight: 400">This creates a clean recovery point on the new timeline. All future PITR restores will use this backup as their starting point, independent of the old Crunchy WAL archive.</span></p>
<p>&nbsp;</p>
<h3><b>Reconnecting your application</b><a class="anchor-link" id="reconnecting-your-application"></a></h3>
<p><span style="font-weight: 400">Update your application&rsquo;s connection string to point at the Percona cluster&rsquo;s pgBouncer service:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">kubectl get service -n $MIGRATION_NS 
  -l postgres-operator.crunchydata.com/cluster=percona-standby,postgres-operator.crunchydata.com/role=pgbouncer</pre>
<p><span style="font-weight: 400">This migration path works almost entirely out of the box. For users coming from the Crunchy Data PostgreSQL Operator, this method feels familiar because it leverages the same standby/replica mechanisms used for HA and disaster recovery. The key difference is that you can now use this familiar mechanism to migrate safely to the Percona PostgreSQL Operator, a fully open-source alternative running on a fully open-source storage layer.</span></p>
<p>&nbsp;</p>
<h3><b>Rollback</b><a class="anchor-link" id="rollback"></a></h3>
<p><span style="font-weight: 400">The standby method is the most rollback-friendly of the three. Until you take the post-migration backup, the Crunchy cluster still holds the original timeline. To roll back:</span></p>
<ol>
<li style="font-weight: 400"><span style="font-weight: 400">Stop writes on the Percona side and patch the Percona cluster back into standby mode (</span><em><span style="font-weight: 400">spec.standby.enabled: true</span></em><span style="font-weight: 400">).</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Patch the Crunchy cluster out of standby mode and let Patroni promote it.</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Verify with </span><em><span style="font-weight: 400">pg_is_in_recovery()</span></em><span style="font-weight: 400"> on both sides.</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Switch the application connection string back to the Crunchy pgBouncer service.</span></li>
</ol>
<p><span style="font-weight: 400">After Step 11 (post-migration backup), the timelines have diverged. From that point, the rollback story is the same as a fresh restore, and you should treat the Crunchy cluster as a historical reference, not a live target.</span></p>
<p>&nbsp;</p>
<h3><b>Troubleshooting</b><a class="anchor-link" id="troubleshooting"></a></h3>
<p><em><strong>Percona standby not connecting to the Crunchy primary. </strong></em><span style="font-weight: 400">Verify the </span><em><span style="font-weight: 400">crunchy-source-ha</span></em><span style="font-weight: 400"> service resolves from within the Percona pod:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">kubectl -n $MIGRATION_NS exec "${STANDBY_POD}" -c database -- 
  bash -c "getent hosts crunchy-source-ha.${MIGRATION_NS}.svc.cluster.local"</pre>
<p><em><b>Replication authentication errors</b></em><span style="font-weight: 400"><em>.</em> The Percona standby authenticates as the </span><span style="font-weight: 400">_crunchyreplication</span><span style="font-weight: 400"> PostgreSQL user using the certificate in </span><span style="font-weight: 400">crunchy-source-replication-cert</span><span style="font-weight: 400">. Verify the secret exists and matches what the Crunchy operator generated:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">kubectl get secret crunchy-source-replication-cert -n $MIGRATION_NS</pre>
<p><em><strong>pgBackRest restore fails</strong><b>.</b></em><span style="font-weight: 400"> Confirm both secrets contain identical credentials and that </span><em><span style="font-weight: 400">repo1-path</span></em><span style="font-weight: 400"> is the same in both cluster specs (</span><em><span style="font-weight: 400">/crunchy-to-percona/repo1</span></em><span style="font-weight: 400"> in this guide). Mismatched paths cause an </span><span style="font-weight: 400"><em>archive.info</em> missing</span><span style="font-weight: 400"> error. Verify the bucket is reachable:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">kubectl run -i --rm s3-check 
  --image=perconalab/awscli 
  --restart=Never 
  -n $MIGRATION_NS 
  -- bash -c "
    AWS_ACCESS_KEY_ID=pgmigration 
    AWS_SECRET_ACCESS_KEY=pgmigration123 
    AWS_DEFAULT_REGION=us-east-1 
    aws --endpoint-url https://seaweedfs-all-in-one.${MIGRATION_NS}.svc.cluster.local:8443 
        --no-verify-ssl 
        s3 ls s3://pg-migration
  "</pre>
<p><em><strong>Timeline history file (00000002.history) missing after promotion.</strong></em> <span style="font-weight: 400"> <span style="font-weight: 400">This is a known </span><a href="https://github.com/CrunchyData/postgres-operator/issues/4472"><span style="font-weight: 400">issue</span></a><span style="font-weight: 400"> with Crunchy PGO&rsquo;s async archive mode. After promotion, push the history file synchronously:</span></span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">kubectl -n $MIGRATION_NS exec "${PERCONA_PRIMARY}" -c database -- 
  bash -c "
    pgbackrest --stanza=db --no-archive-async 
      archive-push "${PGDATA}/pg_wal/00000002.history" || true
  "</pre>
<p>&nbsp;</p>
<h3><b>What&rsquo;s next</b><a class="anchor-link" id="whats-next"></a></h3>
<p><span style="font-weight: 400">This was the safest migration path. </span><strong>Part 3</strong><span style="font-weight: 400"> will cover two simpler options:</span></p>
<ul>
<li style="font-weight: 400"><b>Backup and restore.</b><span style="font-weight: 400"> The simplest path. You take a Crunchy pgBackRest backup and the Percona cluster bootstraps from it. Cutover is the time between the final backup and pointing the application at the new cluster.</span></li>
<li style="font-weight: 400"><b>Persistent volume reuse.</b><span style="font-weight: 400"> For when you want to skip the data copy entirely. The Percona cluster takes over the existing PGDATA volume, no restore step required.</span></li>
</ul>
<p><span style="font-weight: 400">Pick the method that fits your downtime budget, data size, and storage layout.</span></p>
<p><span style="font-weight: 400">This post covers basic deployment patterns and simplified configuration examples. If your environment is more complex, uses custom images, includes Crunchy enterprise features like TDE, or otherwise needs tailored migration steps, contact the Percona team and we will help you plan and execute the move.</span></p>
<p>&nbsp;</p>
<h3><b>Try It Out</b><a class="anchor-link" id="try-it-out"></a></h3>
<ul>
<li style="font-weight: 400"><b>Percona Operator for PostgreSQL docs</b><span style="font-weight: 400">: <a href="https://docs.percona.com/percona-operator-for-postgresql/latest/">https://docs.percona.com/percona-operator-for-postgresql/latest/</a></span></li>
<li style="font-weight: 400"><b>GitHub</b><span style="font-weight: 400">: </span><a href="https://github.com/percona/percona-postgresql-operator"><span style="font-weight: 400">https://github.com/percona/percona-postgresql-operator</span></a></li>
<li style="font-weight: 400"><b>Public roadmap</b><span style="font-weight: 400">: </span><a href="https://github.com/orgs/percona/projects/10/views/6"><span style="font-weight: 400">https://github.com/orgs/percona/projects/10/views/6</span></a></li>
<li style="font-weight: 400"><b>Issue tracker: </b><a href="https://github.com/percona/percona-postgresql-operator/issues"><span style="font-weight: 400">https://github.com/percona/percona-postgresql-operator/issues</span></a></li>
<li style="font-weight: 400"><b>Community Forum</b>: <a href="https://forums.percona.com/c/postgresql/percona-kubernetes-operator-for-postgresql/68">https://forums.percona.com/c/postgresql/percona-kubernetes-operator-for-postgresql/68</a></li>
</ul>
<p>The post <a href="https://www.percona.com/blog/migrate-from-crunchy-data-to-percona-postgresql-operator-standby-cluster/">Migrate from Crunchy Data PostgreSQL Operator to Percona PostgreSQL Operator: Standby Cluster Method</a> appeared first on <a href="https://www.percona.com">Percona</a>.</p>

<p>The post <a rel="nofollow" href="https://www.percona.com/blog/migrate-from-crunchy-data-to-percona-postgresql-operator-standby-cluster/">Migrate from Crunchy Data PostgreSQL Operator to Percona PostgreSQL Operator: Standby Cluster Method</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Write for the Percona Community</title>
      <link>https://percona.community/blog/2026/05/22/write-for-percona-community/</link>
      <pubDate>Fri, 22 May 2026 11:00:00 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://percona.community/blog/">Percona Community Blog - learn about MySQL, MariaDB, PostgreSQL, and MongoDB</source>
      <description><![CDATA[<p>You’ve fixed something gnarly in production this year. You’ve migrated a database that nobody wanted to touch. You’ve built something on top of Percona Operators, or Percona Toolkit, or Percona Monitoring and Management (PMM), and you’ve learned things along the way that aren’t written down anywhere yet.</p>
<p>The post <a rel="nofollow" href="https://percona.community/blog/2026/05/22/write-for-percona-community/">Write for the Percona Community</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>You&rsquo;ve fixed something gnarly in production this year. You&rsquo;ve migrated a database that nobody wanted to touch. You&rsquo;ve built something on top of Percona Operators, or Percona Toolkit, or Percona Monitoring and Management (PMM), and you&rsquo;ve learned things along the way that aren&rsquo;t written down anywhere yet.</p>
<p>Write it up. We&rsquo;ll publish it, and we&rsquo;ll pay you.</p>
<h2 id="what-were-doing">What we&rsquo;re doing<a class="anchor-link" id="what-were-doing"></a></h2>
<p>The Percona Community Writers Program publishes technical posts from the people actually using these tools &mdash; DBAs, developers, contributors, and engineers running real workloads. Posts go up on <a href="https://percona.community/blog" target="_blank" rel="noopener noreferrer">percona.community/blog</a> under your name, with your bio and links.</p>
<p>For every post we publish, you get:</p>
<ul>
<li><strong>$350</strong> paid out after publication</li>
<li><strong>Community engagement points</strong> you can redeem in our swag store for t-shirts, stickers, and other items</li>
</ul>
<p>The points stack across contributions. The more you write, the more you collect.</p>
<h3 id="a-note-on-payment">A note on payment<a class="anchor-link" id="a-note-on-payment"></a></h3>
<p><em>Not everyone can accept payment for writing &mdash; employment contracts, tax situations, visa rules, and conflict-of-interest policies all get in the way. If that&rsquo;s you, we&rsquo;ll donate the same $350 to an open source project or community of your choice on your behalf. Tell us who to send it to when you pitch.</em></p>
<h2 id="what-we-want-to-read">What we want to read<a class="anchor-link" id="what-we-want-to-read"></a></h2>
<p>Anything you&rsquo;ve done with the Percona stack &mdash; or alongside it &mdash; that another engineer would learn from. Some directions to consider:</p>
<ul>
<li><strong>Percona Operators</strong> &mdash; running databases on Kubernetes, scaling decisions, upgrade paths, what surprised you</li>
<li><strong>Percona Toolkit</strong> &mdash; how you use specific tools in your day-to-day, scripts you&rsquo;ve built around them, edge cases</li>
<li><strong>Migrations</strong> &mdash; moving between versions, between database engines, on-premises to cloud, the parts that aren&rsquo;t in the docs</li>
<li><strong>Troubleshooting</strong> &mdash; a real incident, what you saw, what fixed it, what you&rsquo;d do differently</li>
<li><strong>Percona Monitoring and Management (PMM)</strong> &mdash; dashboards you&rsquo;ve built, alerts that actually catch things, integrations</li>
<li><strong>Databases themselves</strong> &mdash; MySQL, PostgreSQL, MongoDB, MariaDB, Valkey, anything in the open source database world you&rsquo;re hands-on with</li>
</ul>
<p>We&rsquo;re not only interested in Percona-product posts. If you&rsquo;re active in the wider open source database community &mdash; contributing to MySQL, PostgreSQL, Valkey, or anywhere else &mdash; we want to hear about that work too. Your projects, your perspective, your hard-won opinions.</p>
<h2 id="standards">Standards<a class="anchor-link" id="standards"></a></h2>
<p>Every submission is reviewed by the community team for technical accuracy and grammar before it goes live. We&rsquo;re not gatekeeping &mdash; we&rsquo;re making sure your name goes on something solid.</p>
<p>One firm rule: <strong>no AI-generated content</strong>. We run every submission through <a href="https://gptzero.me/" target="_blank" rel="noopener noreferrer">GPTZero</a> and it has to come back clean. We&rsquo;re publishing your voice and your experience, not a model&rsquo;s summary of either. If you used AI to help draft, that&rsquo;s fine &mdash; but the post needs to read as yours and pass the check.</p>
<h2 id="how-to-start">How to start<a class="anchor-link" id="how-to-start"></a></h2>
<p>Pitch us first. A couple of sentences on what you want to write about and why you&rsquo;re the person to write it is enough. We&rsquo;ll reply with feedback, a timeline, and any direction that helps you write a stronger post.</p>
<p>You don&rsquo;t need to be a published writer. You need to have done something and be willing to explain how. A 900-word post about how you debugged a replication lag issue last quarter is more valuable than a 3,000-word survey of the database landscape.</p>
<p>Send pitches and questions to the Percona Community team &mdash; by filling in <strong><a href="https://share.hsforms.com/2quoru-zrSli2l-89aiiJggg9e0" target="_blank" rel="noopener noreferrer">this form</a></strong>.</p>
<div class="hs-form-frame" data-region="na1" data-form-id="aaea2bbb-eceb-4a58-b697-ef3d6a288982" data-portal-id="758664"></div>
<h3 id="open-topics-blog-talks-guides">Open topics: blog, talks, guides<a class="anchor-link" id="open-topics-blog-talks-guides"></a></h3>
<p>Not sure where to start? Here are some directions we&rsquo;d love to see covered. Pick one, narrow it down to something you&rsquo;ve actually done, and pitch us.</p>
<p><strong>Databases</strong></p>
<ul>
<li>Automating database setup for production in under a few hours</li>
<li>Backup and disaster recovery strategies that hold up</li>
<li>Failure stories &mdash; what broke, what you learned</li>
</ul>
<p><strong>DevOps and reliability</strong></p>
<ul>
<li>Database Reliability Engineering (DBRE) in practice</li>
<li>Site Reliability Engineering (SRE) applied to databases</li>
<li>Monitoring and SLAs that mean something</li>
<li>Useful scripts you actually run in production</li>
<li>Testing and QA for database changes</li>
</ul>
<p><strong>Distributed computing</strong></p>
<ul>
<li>Consensus algorithms and real-world implementations</li>
<li>Synchronous vs asynchronous replication &mdash; trade-offs and where each fits</li>
</ul>
<p><strong>How-tos</strong></p>
<ul>
<li>Moving from a single node to a cluster (any DB engine)</li>
<li>Batch processing patterns</li>
<li>Stream processing patterns</li>
<li>Metrics that actually tell you something</li>
</ul>
<p><strong>Open source</strong></p>
<ul>
<li>Measuring your open source project&rsquo;s success</li>
<li>Bug squashing done right</li>
<li>Licensing &mdash; what to know before you pick one</li>
<li>Vendor lock-in and how to spot it early</li>
</ul>
<hr>
<p>We pay engineers to share what they&rsquo;ve learned. That&rsquo;s the whole offer. If you&rsquo;ve got something worth writing, write it.</p>

<p>The post <a rel="nofollow" href="https://percona.community/blog/2026/05/22/write-for-percona-community/">Write for the Percona Community</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>MySQL 9.7.0 PGO Benchmark Analysis</title>
      <link>https://www.percona.com/blog/mysql-9-7-0-pgo-benchmark-analysis/</link>
      <pubDate>Fri, 22 May 2026 07:33:49 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://www.percona.com/blog/">Blog - Percona</source>
      <description><![CDATA[<p>Overview Servers Tested: MySQL 9.7.0 (PGO-enabled build released by Oracle) MySQL 9.7.0 Non-PGO (built without Profile-Guided Optimization — see BUILD.md) Tier Configurations: Tier 2G: 2GB InnoDB buffer pool Tier 12G: 12GB InnoDB buffer pool Tier 32G: 32GB InnoDB buffer pool   View Results 📊 Interactive Reports The benchmark reports are available as interactive HTML pages … Continued<br />
The post MySQL 9.7.0 PGO Benchmark Analysis appeared first on Percona.</p>
<p>The post <a rel="nofollow" href="https://www.percona.com/blog/mysql-9-7-0-pgo-benchmark-analysis/">MySQL 9.7.0 PGO Benchmark Analysis</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<h2><b>Overview</b><a class="anchor-link" id="overview"></a></h2>
<p><b>Servers Tested:</b></p>
<ul>
<li style="font-weight: 400"><b>MySQL 9.7.0</b><span style="font-weight: 400"> (PGO-enabled build released by Oracle)</span></li>
<li style="font-weight: 400"><b>MySQL 9.7.0 Non-PGO</b><span style="font-weight: 400"> (built without Profile-Guided Optimization &mdash; see </span><a href="https://github.com/Percona-Lab-results/2026-pgo/blob/main/BUILD.md"><span style="font-weight: 400">BUILD.md</span></a><span style="font-weight: 400">)</span></li>
</ul>
<p><b>Tier Configurations:</b></p>
<ul>
<li style="font-weight: 400"><span style="font-weight: 400">Tier 2G: 2GB InnoDB buffer pool</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Tier 12G: 12GB InnoDB buffer pool</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Tier 32G: 32GB InnoDB buffer pool</span></li>
</ul>
<p>&nbsp;</p>
<h2><b>View Results</b><a class="anchor-link" id="view-results"></a></h2>
<p><span style="font-weight: 400"><img decoding="async" src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4ca.png" alt="&#128202;" class="wp-smiley" style="height: 1em;max-height: 1em"> </span><a href="https://percona-lab-results.github.io/2026-pgo/index.html"><b>Interactive Reports</b></a></p>
<p><span style="font-weight: 400">The benchmark reports are available as interactive HTML pages at:</span></p>
<p><a href="https://percona-lab-results.github.io/2026-pgo/index.html" target="_blank" rel="noopener"><span style="font-weight: 400">https://percona-lab-results.github.io/2026-pgo/index.html</span></a></p>
<h3><b>Performance Graphs</b><a class="anchor-link" id="performance-graphs"></a></h3>
<p><b>Tier 2G (2GB Buffer Pool):</b></p>
<p><b><a href="https://percona-lab-results.github.io/2026-pgo/sysbench_ps_mysql_average.html"><img decoding="async" loading="lazy" class="alignnone wp-image-47783 size-large" src="https://www.percona.com/wp-content/uploads/2026/05/pgo_2G-1024x495.png" alt="" width="1024" height="495"></a></b></p>
<p><b>Tier 12G (12GB Buffer Pool):</b></p>
<p><b> <a href="https://percona-lab-results.github.io/2026-pgo/sysbench_ps_mysql_average.html"><img decoding="async" loading="lazy" class="alignnone wp-image-47784 size-large" src="https://www.percona.com/wp-content/uploads/2026/05/pgo_12G-1024x494.png" alt="" width="1024" height="494"></a></b></p>
<p><b>Tier 32G (32GB Buffer Pool):</b></p>
<p>&nbsp;</p>
<p><b> <a href="https://percona-lab-results.github.io/2026-pgo/sysbench_ps_mysql_average.html"><img decoding="async" loading="lazy" class="alignnone wp-image-47785 size-large" src="https://www.percona.com/wp-content/uploads/2026/05/pgo_32G-1024x494.png" alt="" width="1024" height="494"></a></b></p>
<p>&nbsp;</p>
<h2><b>Key Findings</b><a class="anchor-link" id="key-findings"></a></h2>
<h3><b><br>
Performance Impact of PGO</b><a class="anchor-link" id="performance-impact-of-pgo"></a></h3>
<p><span style="font-weight: 400">MySQL 9.7.0 with Profile-Guided Optimization (PGO) demonstrates measurable performance improvements over the non-PGO build:</span></p>
<p><b><br>
Overall Performance Summary:</b></p>
<ul>
<li style="font-weight: 400"><b>Average improvement: 6.5%</b><span style="font-weight: 400"> across all configurations</span></li>
<li style="font-weight: 400"><b>Peak improvement: 14.3%</b><span style="font-weight: 400"> (Tier 32G, 1 thread), gradually tapering to 10.3% at 512 threads as concurrency increases</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Performance gains range from 0.5% to 14.3% in most scenarios</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Minor regression (-3.1% at Tier 12G, 128 threads)</span></li>
</ul>
<p><b><br>
Performance by Buffer Pool Size:</b></p>
<ul>
<li style="font-weight: 400"><b>Tier 2G</b><span style="font-weight: 400"> (2GB buffer pool): Average improvement of </span><b>3.0%</b></li>
</ul>
<p><span style="font-weight: 400">&ndash; Best gains at 4 threads (5.5% improvement)</span></p>
<p><span style="font-weight: 400">&ndash; Gains range from 0.5% to 5.5% across all thread counts</span></p>
<p><span style="font-weight: 400">&ndash; Modest improvements with no regressions</span></p>
<ul>
<li style="font-weight: 400"><b>Tier 12G</b><span style="font-weight: 400"> (12GB buffer pool): Average improvement of </span><b>4.1%</b></li>
</ul>
<p><span style="font-weight: 400">&ndash; Best gains at 4 threads (8.6% improvement)</span></p>
<p><span style="font-weight: 400">&ndash; Strong gains at low concurrency (1-4 threads: 7.3%-8.6%)</span></p>
<p><span style="font-weight: 400">&ndash; Minor regression at 128 threads (-3.1%), neutral at 512 threads (-0.0%)</span></p>
<ul>
<li style="font-weight: 400"><b>Tier 32G</b><span style="font-weight: 400"> (32GB buffer pool): Average improvement of </span><b>12.2%</b></li>
</ul>
<p><span style="font-weight: 400">&ndash; Consistently strong gains across all thread counts (10.3% to 14.3%)</span></p>
<p><span style="font-weight: 400">&ndash; Peak performance at lowest concurrency (1 thread: 14.3%)</span></p>
<p><span style="font-weight: 400">&ndash; Maintains 11-12% improvement even at highest concurrency (128-512 threads)</span></p>
<p><b><br>
Key Observations:</b></p>
<ul>
<li style="font-weight: 400"><span style="font-weight: 400">PGO provides the most significant benefits with larger buffer pools (32GB tier shows 12.2% average improvement)</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Largest buffer pool configuration benefits from PGO across all concurrency levels with no regressions</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Low to moderate concurrency (1-32 threads) shows best PGO gains across all tiers</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Smaller buffer pools (2GB, 12GB) show more modest improvements and occasional regressions at very high thread counts</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">The performance improvements demonstrate PGO&rsquo;s effectiveness in optimizing hot code paths, particularly when memory resources are abundant</span></li>
</ul>
<h3><b><br>
InnoDB Metrics Analysis</b><a class="anchor-link" id="innodb-metrics-analysis"></a></h3>
<p><span style="font-weight: 400">Deep analysis of InnoDB metrics reveals the source of PGO&rsquo;s performance improvements:</span></p>
<p><b><br>
Root Cause: CPU-Level Optimizations</b></p>
<ul>
<li style="font-weight: 400"><span style="font-weight: 400">PGO improvements are </span><b>NOT</b><span style="font-weight: 400"> from I/O optimization, caching, or lock reduction</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Buffer pool hit ratios remain virtually identical between PGO and non-PGO builds</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Lock contention is minimal in both builds</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">All I/O metrics scale proportionally with increased throughput</span></li>
</ul>
<p><b><br>
What PGO Actually Optimizes:</b></p>
<ul>
<li style="font-weight: 400"><span style="font-weight: 400">&#10003; Better instruction cache utilization</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">&#10003; Improved branch prediction in hot code paths</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">&#10003; Optimized function inlining</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">&#10003; More efficient CPU instruction ordering</span></li>
</ul>
<p><span style="font-weight: 400">The metrics confirm that PGO&rsquo;s 6.5% average improvement comes entirely from making the CPU more efficient at executing MySQL&rsquo;s hot code paths, allowing it to process more transactions per second with the same hardware resources.</span></p>
<p>&nbsp;</p>
<h2><b>What is PGO?</b><a class="anchor-link" id="what-is-pgo"></a></h2>
<p><span style="font-weight: 400">Profile-Guided Optimization (PGO) is a compiler optimization technique that uses runtime profiling data to guide code optimization. The compiler first instruments the code, collects execution profiles during typical workload runs, and then recompiles the code with optimizations targeted at the most frequently executed code paths.</span></p>
<p><b><br>
Benefits of PGO:</b></p>
<ul>
<li style="font-weight: 400"><span style="font-weight: 400">Improved branch prediction</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Better instruction cache utilization</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Optimized function inlining</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Reduced code bloat</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Better register allocation</span></li>
</ul>
<p>&nbsp;</p>
<h2><b>Benchmark Methodology</b><a class="anchor-link" id="benchmark-methodology"></a></h2>
<h3><b><br>
Workload</b><a class="anchor-link" id="workload"></a></h3>
<ul>
<li style="font-weight: 400"><b>Tool</b><span style="font-weight: 400">: Sysbench OLTP Read/Write benchmark</span></li>
<li style="font-weight: 400"><b>Tables</b><span style="font-weight: 400">: 20 tables</span></li>
<li style="font-weight: 400"><b>Table Size</b><span style="font-weight: 400">: 5,000,000 rows per table</span></li>
<li style="font-weight: 400"><b>Thread Counts</b><span style="font-weight: 400">: 1, 4, 16, 32, 64, 128, 256, 512</span></li>
</ul>
<h3><b><br>
Configuration</b><a class="anchor-link" id="configuration"></a></h3>
<ul>
<li style="font-weight: 400"><b>Warmup</b><span style="font-weight: 400">:</span></li>
</ul>
<p><span style="font-weight: 400">&ndash; Read-only: 180 seconds</span></p>
<p><span style="font-weight: 400">&ndash; Read-write: 600 seconds</span></p>
<ul>
<li style="font-weight: 400"><b>Measurement Duration</b><span style="font-weight: 400">: 900 seconds (15 minutes) per thread count</span></li>
<li style="font-weight: 400"><b>Runs</b><span style="font-weight: 400">: Single run per configuration</span></li>
</ul>
<h3><b><br>
System Metrics Collected</b><a class="anchor-link" id="system-metrics-collected"></a></h3>
<ul>
<li style="font-weight: 400"><span style="font-weight: 400">InnoDB storage engine metrics</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">MySQL status variables</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">MySQL system variables</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">System I/O statistics (iostat)</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Virtual memory statistics (vmstat)</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">CPU statistics (mpstat)</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">System statistics (dstat)</span></li>
</ul>
<p>&nbsp;</p>
<h2><b>Appendix</b><a class="anchor-link" id="appendix"></a></h2>
<p><span style="font-weight: 400">For Repository structure, Build steps and Technical details go to </span><a href="https://github.com/Percona-Lab-results/2026-pgo/blob/main/README.md#report-categories"><span style="font-weight: 400">https://github.com/Percona-Lab-results/2026-pgo/blob/main/README.md#report-categories</span></a></p>
<p>&nbsp;</p>
<p>The post <a href="https://www.percona.com/blog/mysql-9-7-0-pgo-benchmark-analysis/">MySQL 9.7.0 PGO Benchmark Analysis</a> appeared first on <a href="https://www.percona.com">Percona</a>.</p>

<p>The post <a rel="nofollow" href="https://www.percona.com/blog/mysql-9-7-0-pgo-benchmark-analysis/">MySQL 9.7.0 PGO Benchmark Analysis</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Knowing when new open source database engine versions release on Amazon Aurora and Amazon RDS</title>
      <link>https://aws.amazon.com/blogs/database/knowing-when-new-open-source-database-engine-versions-release-on-amazon-aurora-and-amazon-rds/</link>
      <pubDate>Thu, 21 May 2026 18:36:46 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://aws.amazon.com/blogs/database/">RDS for MariaDB – AWS Database Blog</source>
      <description><![CDATA[<p>In this post, we share the version currency timelines for Aurora and RDS open source engines. We also explain why timelines differ across engines and how you can use them to plan your upgrades.</p>
<p>The post <a rel="nofollow" href="https://aws.amazon.com/blogs/database/knowing-when-new-open-source-database-engine-versions-release-on-amazon-aurora-and-amazon-rds/">Knowing when new open source database engine versions release on Amazon Aurora and Amazon RDS</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>If you&rsquo;re running or considering <a href="https://aws.amazon.com/rds/aurora/" target="_blank" rel="noopener">Amazon Aurora</a> with PostgreSQL or MySQL compatibility, you&rsquo;ve likely wondered, &ldquo;When will the latest community version be available on AWS?&rdquo; The same question applies if you run <a href="https://aws.amazon.com/rds/" target="_blank" rel="noopener">Amazon Relational Database Service</a> (Amazon RDS) for PostgreSQL, MySQL, or MariaDB. Whether you want the newest features quickly or prefer to standardize on stable long-term support (LTS) versions, our release timelines help you plan upgrades and maintenance cycles. In this post, we share the version currency timelines for Aurora and RDS open source engines. We also explain why timelines differ across engines and how you can use them to plan your upgrades.</p>
<p>Today, we are publishing version currency timelines for Aurora and RDS open source engines. The timelines apply to new major and minor versions going forward and define when you and your teams can expect new versions on AWS. With this predictability, you can plan maintenance windows, upgrade cycles, and Aurora LTS adoption for workloads that prioritize long-term stability.</p>
<table border="1px" cellpadding="10px" width="100%">
<tbody>
<tr style="background-color: black;color: white">
<td><strong>Database engine</strong></td>
<td><strong>Release type</strong></td>
<td><strong>Timeline</strong></td>
</tr>
<tr>
<td rowspan="2"><strong><a href="https://docs.aws.amazon.com/AmazonRDS/latest/PostgreSQLReleaseNotes/postgresql-release-calendar.html" rel="noopener" target="_blank">RDS for PostgreSQL</a></strong></td>
<td>Minor versions</td>
<td>Within 7 days of community release</td>
</tr>
<tr>
<td>Major versions</td>
<td>Within 30 days of the community <code>&lt;major&gt;.1</code> release</td>
</tr>
<tr>
<td rowspan="2"><strong><a href="https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/MySQL.Concepts.VersionMgmt.html" rel="noopener" target="_blank">RDS for MySQL</a></strong></td>
<td>Minor versions</td>
<td>Within 30 days of community release</td>
</tr>
<tr>
<td>Major versions</td>
<td>Within 6 months of community <code>&lt;major&gt;.1</code> release (Oracle MySQL LTS majors)</td>
</tr>
<tr>
<td rowspan="2"><strong><a href="https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/MariaDB.Concepts.VersionMgmt.html" rel="noopener" target="_blank">RDS for MariaDB</a></strong></td>
<td>Minor versions</td>
<td>Within 30 days of community release</td>
</tr>
<tr>
<td>Major versions</td>
<td>Within 3 months of community&rsquo;s first patch release</td>
</tr>
<tr>
<td rowspan="3"><strong><a href="https://docs.aws.amazon.com/AmazonRDS/latest/AuroraPostgreSQLReleaseNotes/aurorapostgresql-release-calendar.html" rel="noopener" target="_blank">Aurora PostgreSQL</a></strong></td>
<td>Minor versions</td>
<td>Within 3 months of community release</td>
</tr>
<tr>
<td>Major versions</td>
<td>Within 8 months of the community <code>&lt;major&gt;.1</code> release</td>
</tr>
<tr>
<td>Aurora LTS per major</td>
<td>Within 12 months of Aurora major GA</td>
</tr>
<tr>
<td rowspan="3"><strong><a href="https://docs.aws.amazon.com/AmazonRDS/latest/AuroraMySQLReleaseNotes/AuroraMySQL.release-calendars.html" rel="noopener" target="_blank">Aurora MySQL</a></strong></td>
<td>Minor versions</td>
<td>Within 3 months of community release</td>
</tr>
<tr>
<td>Major versions</td>
<td>Within 12 months of community <code>&lt;major&gt;.1</code> release (Oracle MySQL LTS majors)</td>
</tr>
<tr>
<td>Aurora LTS per major</td>
<td>Within 12 months of Aurora major GA</td>
</tr>
</tbody>
</table>
<p>For the current schedule of upcoming and recently shipped versions, including specific version numbers and target dates, see the release calendar linked from each engine name in the table. </p>
<h2>Why timelines differ across engines<a class="anchor-link" id="why-timelines-differ-across-engines"></a></h2>
<p>The timelines differ by engine because the upstream development and integration models differ. PostgreSQL and MariaDB communities develop in the open, which lets us start validation early. MySQL commits are available closer to public releases. RDS runs the community engine on managed infrastructure, so after a community release passes validation it can ship quickly. Aurora adds a distributed storage layer, Global Database, and serverless capabilities underneath PostgreSQL- and MySQL-compatible engines. Every new version goes through additional validation to verify that those capabilities continue to function correctly. This is why Aurora timelines are longer than RDS timelines for the same engine. Aurora also offers Long-Term Support releases for multi-year stability on a single minor version.</p>
<h2>How we choose major version starting points<a class="anchor-link" id="how-we-choose-major-version-starting-points"></a></h2>
<p>For PostgreSQL, our first production release of a new major version is typically based on the community <code>&lt;major&gt;.1</code> release rather than <code>&lt;major&gt;.0</code>. The <code>&lt;major&gt;.1</code> release generally arrives roughly three months after the initial major release. It incorporates the first round of bug fixes and security patches identified during early production deployments, which provides a more stable starting point for production workloads.</p>
<p>MariaDB follows a similar pattern. The published major version timelines are measured from the community&rsquo;s first patch release for a new major version rather than the initial <code>&lt;major&gt;.0</code> release. This gives customers a more mature production baseline to target.</p>
<p>For MySQL, the major version timelines apply to Oracle MySQL LTS major releases and are measured from the corresponding <code>&lt;major&gt;.1</code> release. This aligns the timelines to the first patch release after the initial LTS major becomes generally available.</p>
<h2>What this means for your upgrade planning<a class="anchor-link" id="what-this-means-for-your-upgrade-planning"></a></h2>
<p>Published version currency timelines give you and your teams earlier visibility into release planning and upgrade scheduling. With RDS for PostgreSQL minor versions arriving within 7 days of community release, teams can stay current on security patches and bug fixes with relatively little operational planning. You can enable automatic minor version upgrades to receive patches during maintenance windows. You can also use <a href="https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_upgrade_rollout.html" rel="noopener" target="_blank">AWS Organizations upgrade rollout policies</a> to manage deployment sequencing across your development, test, and production environments, or apply upgrades manually based on your own operational processes.</p>
<p>Earlier visibility into major version timelines helps your teams adopt new database capabilities on your own schedule. Knowing when a new version is expected on Aurora or RDS gives teams more time to review release notes, validate application behavior, and prepare rollout plans ahead of adoption. With RDS Database Preview, you get early access to PostgreSQL and MySQL major versions in a non-production environment so you can test application compatibility in advance. With Blue/Green Deployments, you can validate changes before cutover and transition production traffic with minimal downtime.</p>
<p>With Aurora LTS releases, you can prioritize operational stability over rapid feature adoption. Your teams can remain on a stable minor baseline for multiple years while aligning major version upgrades with broader application and infrastructure roadmaps.</p>
<p>For workloads approaching or beyond community end-of-life timelines, Amazon RDS Extended Support gives you additional time to finish upgrades while continuing to receive critical security updates.</p>
<h2>Learn more<a class="anchor-link" id="learn-more"></a></h2>
<p>For detailed upgrade procedures and release guidance, see the <a href="https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/CHAP_AuroraOverview.html" target="_blank" rel="noopener">Amazon Aurora User Guide</a> and the <a href="https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Welcome.html" target="_blank" rel="noopener">Amazon RDS User Guide</a>.</p>
<hr>
<h2>About the authors<a class="anchor-link" id="about-the-authors"></a></h2>
<footer>
<div class="blog-author-box">
<div class="blog-author-image">
   <img decoding="async" loading="lazy" class="alignleft size-full" src="https://d2908q01vomqb2.cloudfront.net/887309d048beef83ad3eabf2a79a64a389ab1c9f/2026/05/18/DB5644a1.jpg" alt="Betty Chun" width="100" height="100">
  </div>
<h3 class="lb-h4">Betty Chun<a class="anchor-link" id="betty-chun"></a></h3>
<p><a target="_blank" href="https://www.linkedin.com/in/betty-chun-3b8811/" rel="noopener">Betty</a> is a Principal Product Marketing Manager at AWS. She focuses on relational database services, such as Amazon Aurora. She is based on Seattle and enjoys cooking and the outdoors.</p>
</div>
<div class="blog-author-box">
<div class="blog-author-image">
   <img decoding="async" loading="lazy" class="aligncenter size-full wp-image-29797" src="https://d2908q01vomqb2.cloudfront.net/887309d048beef83ad3eabf2a79a64a389ab1c9f/2025/11/24/DBBLOG-5173-14.png" alt="Keyur Diwan" width="120" height="160">
  </div>
<h3 class="lb-h4">Keyur Diwan<a class="anchor-link" id="keyur-diwan"></a></h3>
<p><a href="https://www.linkedin.com/in/keyurdiwan/" target="_blank" rel="noopener">Keyur</a> is a Principal Product Manager with Amazon Aurora/RDS in Seattle, where he builds next-generation capabilities in managed PostgreSQL, Blue/Green deployments, seamless upgrades, security, and analytics technologies such as HTAP, ZETL, and CDC streaming.</p>
</div>
<div class="blog-author-box">
<div class="blog-author-image">
   <img decoding="async" loading="lazy" class="aligncenter size-full wp-image-29797" src="https://d2908q01vomqb2.cloudfront.net/887309d048beef83ad3eabf2a79a64a389ab1c9f/2025/12/11/DBBLOG-5252-2.jpeg" alt="Abhinav Dhandh" width="120" height="160">
  </div>
<h3 class="lb-h4">Abhinav Dhandh<a class="anchor-link" id="abhinav-dhandh"></a></h3>
<p><a target="_blank" href="https://www.linkedin.com/in/abhinav-dhandh-35139418/" rel="noopener">Abhinav</a> is a product management leader for Amazon Aurora and Amazon RDS Open Source databases. He is responsible for driving developer experiences, agentic AI, and scale out charter. Abhinav has led critical initiatives for managed open source database strategy, zero-ETL and change data capture (CDC), migrations, and commitment-based pricing.</p>
</div>
</footer>

<p>The post <a rel="nofollow" href="https://aws.amazon.com/blogs/database/knowing-when-new-open-source-database-engine-versions-release-on-amazon-aurora-and-amazon-rds/">Knowing when new open source database engine versions release on Amazon Aurora and Amazon RDS</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>AI-Assisted Production Database Ops with ClusterControl MCP and CCX MCP</title>
      <link>https://severalnines.com/blog/ai-assisted-production-database-ops-with-clustercontrol-mcp-and-ccx-mcp/</link>
      <pubDate>Thu, 21 May 2026 10:22:01 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://severalnines.com/">Severalnines</source>
      <description><![CDATA[<p>In December, we introduced how Model Context Protocol could make ClusterControl easier to work with from AI assistants. Since then, Severalnines has expanded that MCP direction across its database operations platforms with ClusterControl MCP and CCX MCP. The latest ClusterControl MCP is the major update, providing a more robust implementation with 69 tools and 20 […]<br />
The post AI-Assisted Production Database Ops with ClusterControl MCP and CCX MCP appeared first on Severalnines.</p>
<p>The post <a rel="nofollow" href="https://severalnines.com/blog/ai-assisted-production-database-ops-with-clustercontrol-mcp-and-ccx-mcp/">AI-Assisted Production Database Ops with ClusterControl MCP and CCX MCP</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>In December, we introduced how Model Context Protocol could make <a href="https://severalnines.com/clustercontrol">ClusterControl</a> easier to work with from AI assistants. Since then, Severalnines has expanded that MCP direction across its database operations platforms with <strong>ClusterControl MCP</strong> and <strong>CCX MCP</strong>.</p>
<p>The latest ClusterControl MCP is the major update, providing a more robust implementation with <strong>69 tools and 20 MCP resources / templates</strong> for production database operations across ClusterControl-managed environments. CCX MCP is the companion MCP server for <a href="https://severalnines.com/ccx">CCX</a>, bringing AI-assisted workflows to managed cloud database operations.</p>
<p>Together, they give Severalnines users a practical way to inspect, troubleshoot, and act on database infrastructure from MCP-compatible clients such as Claude Desktop, Claude Code, OpenAI Codex, and other tools that support MCP.</p>
<h2 class="wp-block-heading" id="h-what-is-new-in-clustercontrol-mcp">What is new in ClusterControl MCP?<a class="anchor-link" id="what-is-new-in-clustercontrol-mcp"></a></h2>
<p>ClusterControl MCP 1.0 moves beyond the earlier MCP concept and provides broader coverage across daily database operations. You can ask questions such as:</p>
<ul class="wp-block-list">
<li>&ldquo;List all my database clusters and their status.&rdquo;</li>
<li>&ldquo;Show me the topology of cluster 2.&rdquo;</li>
<li>&ldquo;Are there any active alarms across all clusters?&rdquo;</li>
<li>&ldquo;What backup jobs have run on cluster 3?&rdquo;</li>
<li>&ldquo;Show me the top queries by wait time on cluster 1.&rdquo;</li>
<li>&ldquo;Are there any tables without primary keys?&rdquo;</li>
<li>&ldquo;Show me recent transaction deadlocks.&rdquo;</li>
<li>&ldquo;List the log files collected from cluster 1.&rdquo;</li>
<li>&ldquo;Who made changes to cluster 3 in the last hour?&rdquo;</li>
</ul>
<p>You can also prepare actions such as:</p>
<ul class="wp-block-list">
<li>&ldquo;Run a backup on cluster 1 right now.&rdquo;</li>
<li>&ldquo;Create a nightly backup schedule at 02:00.&rdquo;</li>
<li>&ldquo;Put db1.example.com into maintenance from 22:00 to 23:00 UTC.&rdquo;</li>
<li>&ldquo;Create a read-only database user for reporting.&rdquo;</li>
<li>&ldquo;Set max_connections to 500 on db1.example.com.&rdquo;</li>
<li>&ldquo;Restore backup #42 to cluster 1.&rdquo;</li>
</ul>
<p>Write operations use a dry-run-first model. The assistant describes what would happen before anything is executed, and high-risk operations include extra warnings.</p>
<h2 class="wp-block-heading" id="h-example-move-from-alarm-to-evidence-faster">Example: move from alarm to evidence faster<a class="anchor-link" id="example-move-from-alarm-to-evidence-faster"></a></h2>
<p>A common operational flow starts with a broad question:</p>
<p>&ldquo;Are there any active alarms across all clusters?&rdquo;</p>
<p>From there, you can drill down:</p>
<ul class="wp-block-list">
<li>&ldquo;Show me alarms for cluster 3.&rdquo;</li>
<li>&ldquo;Show me the CMON log for cluster 3 from the last hour.&rdquo;</li>
<li>&ldquo;Summarize the warnings by component and hostname.&rdquo;</li>
</ul>
<p>That is where the 1.0 implementation becomes useful. It is not just returning a static dashboard view. It can help you move across related operational data: alarms, jobs, CMON controller logs, database server logs, topology, backup history, maintenance windows, and audit events.</p>
<h2 class="wp-block-heading" id="h-example-inspect-and-manage-backups-conversationally">Example: inspect and manage backups conversationally<a class="anchor-link" id="example-inspect-and-manage-backups-conversationally"></a></h2>
<p>Backups are another area where ClusterControl MCP 1.0 adds practical coverage. You can ask:</p>
<ul class="wp-block-list">
<li>&ldquo;When was the last successful backup on my MongoDB cluster?&rdquo;</li>
<li>&ldquo;Show me only failed backups on cluster 1.&rdquo;</li>
<li>&ldquo;Does cluster 1 have a backup schedule configured?&rdquo;</li>
</ul>
<p>And then prepare a change:</p>
<p>&ldquo;Create a nightly backup schedule at 02:00 on cluster 1 using xtrabackup.&rdquo;</p>
<p>The assistant first returns a dry-run preview. Only after confirmation does it execute the change.</p>
<h2 class="wp-block-heading" id="h-installing-clustercontrol-mcp">Installing ClusterControl MCP<a class="anchor-link" id="installing-clustercontrol-mcp"></a></h2>
<p>ClusterControl MCP packages are published through the Severalnines repository alongside other ClusterControl components.</p>
<p>Debian / Ubuntu:</p>
<pre class="wp-block-code"><code>apt-get install clustercontrol-mcp</code></pre>
<p>RHEL / Rocky / AlmaLinux:</p>
<pre class="wp-block-code"><code>yum install clustercontrol-mcp</code></pre>
<p>The binary installs to:</p>
<pre class="wp-block-code"><code>/usr/bin/cmon-mcp</code></pre>
<p>The package also installs:</p>
<pre class="wp-block-code"><code>/etc/systemd/system/cmon-mcp.service
/etc/default/cmon-mcp</code></pre>
<h2 class="wp-block-heading" id="h-setting-up-clustercontrol-mcp-in-stdio-mode">Setting up ClusterControl MCP in stdio mode<a class="anchor-link" id="setting-up-clustercontrol-mcp-in-stdio-mode"></a></h2>
<p>First, we&rsquo;ll start with stdio mode for when the AI client runs the MCP server locally, such as Claude Desktop or Claude Code.</p>
<p>Claude Desktop configuration:</p>
<pre class="wp-block-code"><code>{
 "mcpServers": {
   "clustercontrol": {
     "command": "cmon-mcp",
     "env": {
       "CMON_ENDPOINT": "https://your-cc-host:9501",
       "CMON_USERNAME": "admin",
       "CMON_PASSWORD": "your-password"
     }
   }
 }
}</code></pre>
<p>Restart Claude Desktop. The hammer icon confirms that the MCP server loaded.</p>
<p>For Claude Code:</p>
<pre class="wp-block-code"><code>claude mcp add clustercontrol -- cmon-mcp 
 -endpoint https://your-cc-host:9501 
 -username admin 
 -password your-password</code></pre>
<h2 class="wp-block-heading" id="h-setting-up-clustercontrol-mcp-in-http-mode">Setting up ClusterControl MCP in HTTP mode<a class="anchor-link" id="setting-up-clustercontrol-mcp-in-http-mode"></a></h2>
<p>Use HTTP mode for OpenAI Codex, team access, or multi-client access. Edit:</p>
<pre class="wp-block-code"><code>/etc/default/cmon-mcp</code></pre>
<p>Example:</p>
<pre class="wp-block-code"><code>CMON_ENDPOINT=https://127.0.0.1:9501
CMON_USERNAME=admin
CMON_KEY_FILE=/etc/clustercontrol/id_rsa

MCP_BIND_ADDRESS=0.0.0.0:3000
MCP_BASE_URL=http://your-cc-host:3000
MCP_AUTH_TOKEN=&lt;your-strong-random-token&gt;</code></pre>
<p>Generate a strong token:</p>
<pre class="wp-block-code"><code>openssl rand -hex 32</code></pre>
<p>Restart the service:</p>
<pre class="wp-block-code"><code>systemctl restart cmon-mcp
journalctl -u cmon-mcp -n 20</code></pre>
<p>Connect OpenAI Codex:</p>
<pre class="wp-block-code"><code>codex --mcp-server-uri http://your-cc-host:3000/mcp 
     --mcp-header "Authorization: Bearer &lt;your-token&gt;"</code></pre>
<p>Connect Claude Code over SSE:</p>
<pre class="wp-block-code"><code>claude mcp add clustercontrol --transport sse http://your-cc-host:3000/sse 
 --header "Authorization: Bearer &lt;your-token&gt;"</code></pre>
<p>Connect Claude Desktop over SSE:</p>
<pre class="wp-block-code"><code>{
 "mcpServers": {
   "clustercontrol": {
     "type": "sse",
     "url": "http://your-cc-host:3000/sse",
     "headers": {
       "Authorization": "Bearer &lt;your-token&gt;"
     }
   }
 }
}</code></pre>
<h2 class="wp-block-heading" id="h-ccx-mcp-ai-assisted-workflows-for-ccx">CCX MCP: AI-Assisted Workflows for CCX<a class="anchor-link" id="ccx-mcp-ai-assisted-workflows-for-ccx"></a></h2>
<p>As noted upfront, <strong>CCX MCP</strong> brings the MCP-based workflow to Severalnines users running managed cloud databases in CCX. It lets MCP-compatible AI clients interact with CCX datastores, cloud providers, plans, databases, users, firewall rules, backups, parameter groups, and performance data.</p>
<p>Typical prompts include:</p>
<ul class="wp-block-list">
<li>&ldquo;List my datastores.&rdquo;</li>
<li>&ldquo;Create a PostgreSQL cluster.&rdquo;</li>
<li>&ldquo;Get the connection string for my production database.&rdquo;</li>
<li>&ldquo;Add 10.0.0.0/24 as a trusted source.&rdquo;</li>
<li>&ldquo;Show me the slowest queries.&rdquo;</li>
<li>&ldquo;List available backups for this datastore.&rdquo;</li>
</ul>
<p>CCX MCP supports PostgreSQL, MySQL / Percona, MariaDB, Redis, Valkey, and Microsoft SQL Server. It also includes protection behavior for destructive operations, which are blocked by default unless protection is explicitly disabled.</p>
<h2 class="wp-block-heading" id="h-installing-and-setting-up-ccx-mcp">Installing and setting up CCX MCP<a class="anchor-link" id="installing-and-setting-up-ccx-mcp"></a></h2>
<p>CCX MCP can be installed from npm:</p>
<pre class="wp-block-code"><code>npm install @severalnines/ccx-mcp</code></pre>
<p>Or used directly through <code>npx</code> in your MCP client configuration:</p>
<pre class="wp-block-code"><code>{
 "mcpServers": {
   "ccx": {
     "command": "npx",
     "args": ["-y", "@severalnines/ccx-mcp"],
     "env": {
       "CCX_BASE_URL": "https://app.myccx.io",
       "CCX_USERNAME": "your-email@example.com",
       "CCX_PASSWORD": "your-password"
     }
   }
 }
}</code></pre>
<p>OAuth2 is also supported:</p>
<pre class="wp-block-code"><code>{
 "CCX_CLIENT_ID": "your-client-id",
 "CCX_CLIENT_SECRET": "your-client-secret"
}</code></pre>
<h3 class="wp-block-heading" id="h-claude-code">Claude Code<a class="anchor-link" id="claude-code"></a></h3>
<p>For Claude Code, register the CCX MCP server in one command. No manual config file editing is required:</p>
<pre class="wp-block-code"><code>claude mcp add ccx -- npx -y @severalnines/ccx-mcp@latest 
 --endpoint https://app.myccx.io 
 --client-id &lt;your-client-id&gt; 
 --client-secret &lt;your-client-secret&gt;</code></pre>
<p>Create OAuth2 credentials in the CCX UI under <strong>Account &gt; Security</strong>.</p>
<p>Then restart Claude Code, or run <code>/mcp</code> and reconnect. After that, you are ready to start using CCX MCP from your Claude Code session.</p>
<h2 class="wp-block-heading" id="h-wrapping-up">Wrapping up<a class="anchor-link" id="wrapping-up"></a></h2>
<p>The original ClusterControl MCP work showed how AI assistants could become useful in database operations when connected to the right operational context. The latest version makes that idea much more complete, providing a broader and safer operational interface across clusters, jobs, alarms, backups, logs, performance, users, maintenance, audit, and configuration. <a href="https://docs.severalnines.com/clustercontrol/latest/reference-manuals/clustercontrol-mcp/">Go here for more information on how it works and detailed documentation.</a></p>
<p>For CCX and service provider users, CCX MCP provides the companion interface for managed cloud database operations. Together, they give database teams a practical way to use AI where it matters: inside real operational workflows, with context, control, and safety.</p>
<p>The post <a href="https://severalnines.com/blog/ai-assisted-production-database-ops-with-clustercontrol-mcp-and-ccx-mcp/">AI-Assisted Production Database Ops with ClusterControl MCP and CCX MCP</a> appeared first on <a href="https://severalnines.com">Severalnines</a>.</p>

<p>The post <a rel="nofollow" href="https://severalnines.com/blog/ai-assisted-production-database-ops-with-clustercontrol-mcp-and-ccx-mcp/">AI-Assisted Production Database Ops with ClusterControl MCP and CCX MCP</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Vibe-coding an Audit Plugin in Under 3 Minutes</title>
      <link>https://mariadb.org/vibe-coding-an-audit-plugin-in-under-3-minutes/</link>
      <pubDate>Thu, 21 May 2026 09:06:36 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.org/">MariaDB.org</source>
      <description><![CDATA[<p>Who says developing MariaDB plugins is hard? I was able to produce one in under 3 minutes!<br />
I of course did it by asking Grok nicely:<br />
The produced result is actually very decent:<br />
It even produced a Makefile:<br />
And compilation instructions:<br />
While I had Grok’s attention I’ve given it a follow up task:<br />
Note the “please” …<br />
Continue reading \"Vibe-coding an Audit Plugin in Under 3 Minutes\"<br />
The post Vibe-coding an Audit Plugin in Under 3 Minutes appeared first on MariaDB.org.</p>
<p>The post <a rel="nofollow" href="https://mariadb.org/vibe-coding-an-audit-plugin-in-under-3-minutes/">Vibe-coding an Audit Plugin in Under 3 Minutes</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>Who says developing MariaDB plugins is hard? I was able to produce one in under 3 minutes!<br>
I of course did it by asking Grok nicely:<br>
The produced result is actually very decent:<br>
It even produced a Makefile:<br>
And compilation instructions:<br>
While I had Grok&rsquo;s attention I&rsquo;ve given it a follow up task:<br>
Note the &ldquo;please&rdquo; &hellip; </p>
<p class="link-more"><a href="https://mariadb.org/vibe-coding-an-audit-plugin-in-under-3-minutes/" class="more-link">Continue reading<span class="screen-reader-text"> &ldquo;Vibe-coding an Audit Plugin in Under 3 Minutes&rdquo;</span></a></p>
<p>The post <a rel="nofollow" href="https://mariadb.org/vibe-coding-an-audit-plugin-in-under-3-minutes/">Vibe-coding an Audit Plugin in Under 3 Minutes</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>

<p>The post <a rel="nofollow" href="https://mariadb.org/vibe-coding-an-audit-plugin-in-under-3-minutes/">Vibe-coding an Audit Plugin in Under 3 Minutes</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Stop Paying for Air: Most Cloud Database Spend Is Wasted</title>
      <link>https://mariadb.com/resources/blog/stop-paying-for-air-most-cloud-database-spend-is-wasted/</link>
      <pubDate>Wed, 20 May 2026 15:58:06 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.com/">MariaDB</source>
      <description><![CDATA[<p>This blog was originally published on SkySQL’s website. The Hidden Cost of Idle Cloud Databases Structured databases are amongst the biggest […]</p>
<p>The post <a rel="nofollow" href="https://mariadb.com/resources/blog/stop-paying-for-air-most-cloud-database-spend-is-wasted/">Stop Paying for Air: Most Cloud Database Spend Is Wasted</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>This blog was originally published on SkySQL&rsquo;s website. Structured databases are amongst the biggest line items in enterprise IT infrastructure &ndash; and a significant share of that spend is simply wasted. According to Harness&rsquo;s FinOps in Focus 2025 report, an estimated 21% of enterprise cloud infrastructure spend &ndash; equivalent to $44.5 billion in 2025 &ndash; goes to&hellip;</p>
<p><a href="https://mariadb.com/resources/blog/stop-paying-for-air-most-cloud-database-spend-is-wasted/" rel="nofollow">Source</a></p>

<p>The post <a rel="nofollow" href="https://mariadb.com/resources/blog/stop-paying-for-air-most-cloud-database-spend-is-wasted/">Stop Paying for Air: Most Cloud Database Spend Is Wasted</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>CVE-2026-8053: “We don’t use time-series” is not a mitigation</title>
      <link>https://www.percona.com/blog/cve-2026-8053-we-dont-use-time-series-is-not-a-mitigation/</link>
      <pubDate>Wed, 20 May 2026 15:13:41 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://www.percona.com/blog/">Blog - Percona</source>
      <description><![CDATA[<p>TL;DR: A bug in MongoDB’s time-series collection code allows a user with the standard readWrite role to corrupt memory within the mongod process. Best case: your database crashes, and you spend the night writing a postmortem. Worst case: an attacker is running their code as mongod, with the same access to your data that the … Continued<br />
The post CVE-2026-8053: “We don’t use time-series” is not a mitigation appeared first on Percona.</p>
<p>The post <a rel="nofollow" href="https://www.percona.com/blog/cve-2026-8053-we-dont-use-time-series-is-not-a-mitigation/">CVE-2026-8053: “We don’t use time-series” is not a mitigation</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p><strong>TL;DR:</strong> A bug in MongoDB&rsquo;s time-series collection code allows a user with the standard <code>readWrite</code><br>
role to corrupt memory within the <code>mongod</code> process. Best case: your database crashes, and you spend the night writing a postmortem. Worst case: an attacker is running their code as <code>mongod</code>, with the same access to your data that the database process itself has &mdash; every collection on that node, every index, every secret stored in it. The patch for Percona Server for MongoDB 7.0 is already available; 8.0 will be available tomorrow, and 6.0 will be available early next week.</p>
<p><img decoding="async" loading="lazy" class="aligncenter wp-image-47736 size-full" src="https://www.percona.com/wp-content/uploads/2026/05/blog-hero-CVE-2026-8053.png" alt="" width="1600" height="900"></p>
<p>Every time a bug like this lands, the same conversation plays out in incident channels across the industry. <em>Are we affected? We don&rsquo;t even use time-series collections!</em>&nbsp;Heads nod. Everyone moves on.</p>
<p><strong>That&rsquo;s the mistake.</strong></p>
<p>CVE-2026-8053 is an out-of-bounds memory write in MongoDB&rsquo;s time-series collection &mdash; specifically in the internal mapping between measurement field names and column indexes. Under the right input, the mapping drifts out of sync with the underlying buffer and <code>mongod</code> writes off the end of an allocation. From there, under the right conditions, you can execute arbitrary code as the database process.</p>
<p><img decoding="async" loading="lazy" class="aligncenter wp-image-47737 size-full" src="https://www.percona.com/wp-content/uploads/2026/05/blog-attack-flow-CVE-2026-8053.png" alt="" width="1600" height="620"></p>
<p>Upstream tracking lives at <a href="https://jira.mongodb.org/browse/SERVER-126021">SERVER-126021</a>. CVSS v3.1 puts it at 8.8. CVSS v4.0 puts it at 8.7. The labels say &ldquo;High.&rdquo; How that &ldquo;High&rdquo; translates into your week depends on a couple of assumptions worth questioning.</p>
<p>Read literally, the prerequisite is &ldquo;an authenticated user with database write privileges.&rdquo; Read operationally, that bar is lower than most teams treat it as.</p>
<h3>The mitigation you think you have doesn&rsquo;t exist<a class="anchor-link" id="the-mitigation-you-think-you-have-doesnt-exist"></a></h3>
<p><span style="font-weight: 400">Modern stacks have dozens of service accounts, with secrets scattered across config files, pipelines, and laptops you&rsquo;ve long forgotten about. Others end up in log files on bad days. And every user with write access to your cluster sits one step away from the vulnerable code path. In a world like that, &ldquo;the attacker would need credentials first&rdquo; isn&rsquo;t a speed bump &mdash; it&rsquo;s a shrug.</span></p>
<p><span style="font-weight: 400">So the real question was never authenticated vs. unauthenticated. It&rsquo;s what authentication unlocks. Here, it unlocks Remote Code Execution (RCE), which is exactly what the CVSS score is trying to tell you &mdash; even if the industry&rsquo;s reaction hasn&rsquo;t quite caught up. Attackers don&rsquo;t need your time-series collection to already exist &ndash; they just need someone&rsquo;s credentials in the wrong hands, and there are more ways for that to happen than most teams want to admit.</span></p>
<p><span style="font-weight: 400">I&rsquo;m not raising this to be smug. I&rsquo;m raising it because too many incident channels keep stalling on the wrong question. It isn&rsquo;t: </span><i><span style="font-weight: 400">&ldquo;Does our app use time-series?&rdquo;</span></i><span style="font-weight: 400"> It&rsquo;s: </span><i><span style="font-weight: 400">&ldquo;What can a user holding our readWrite role actually do this week?&rdquo;</span></i></p>
<p><span style="font-weight: 400">Until you patch, the answer is more than you think.</span></p>
<h3>What Percona is shipping, and when?<a class="anchor-link" id="what-percona-is-shipping-and-when"></a></h3>
<ul>
<li><a href="https://docs.percona.com/percona-server-for-mongodb/7.0/release_notes/7.0.34-19.html"><strong>Percona Server for MongoDB 7.0.34-19</strong></a> &mdash; May 20, 2026</li>
<li><strong>Percona Server for MongoDB 8.0.23-10 </strong>&mdash; May 21, 2026</li>
<li><strong>Percona Server for MongoDB 6.0.28-22</strong> &mdash; May 25, 2026</li>
</ul>
<p>6.0 is on the End-Of-Life (EOL) track. The easy call would be to point at the lifecycle page, note that the upgrade conversation is overdue, and stop there. We&rsquo;re shipping the fix anyway. Customers running 6.0 in production have real reasons they haven&rsquo;t migrated yet &mdash; frozen application stacks, certification cycles, dependencies that don&rsquo;t move on quarterly cadences &mdash; and none of those reasons are worth exploiting while a migration plan gets approved.</p>
<p>Percona is <strong>not</strong> building binary packages for the 5.x line. We&rsquo;re being upfront about that &mdash; the calculus on extended support has a limit, and 5.x is past it for us. But the fix itself is already in our public release branch: <a href="https://github.com/percona/percona-server-mongodb/tree/release-5.0.33-26">release-5.0.33-26</a>. If you have a hard requirement on 5.x and the time pressure to meet it, the source is available for building. Percona customers on 5.x can open a ticket, and we&rsquo;ll work on the case individually.</p>
<h3>What to do this week?<a class="anchor-link" id="what-to-do-this-week"></a></h3>
<p>Patch! Specifically:</p>
<ul>
<li>If you&rsquo;re on <strong>7.0</strong>, upgrade to 7.0.34-19 from <strong>May 20</strong> onward.</li>
<li>If you&rsquo;re on <strong>8.0</strong>, upgrade to 8.0.23-10 from <strong>May 21</strong> onward.</li>
<li>If you&rsquo;re on <strong>6.0</strong>, upgrade to 6.0.28-22 from <strong>May 25</strong> onward.</li>
<li>If you&rsquo;re on <strong>5.0</strong>&nbsp;and you can&rsquo;t move, build from <a href="https://github.com/percona/percona-server-mongodb/tree/release-5.0.33-26">release-5.0.33-26</a>. Customers &mdash; open a ticket and we&rsquo;ll help.</li>
</ul>
<p>As usual, you can download patches from your package manager or Percona <a href="https://www.percona.com/downloads/">Software Downloads</a> page.</p>
<p>If you&rsquo;re running PSMDB <strong>on Kubernetes via the Percona Operator for MongoDB</strong>, edit the image tag in your <code>PerconaServerMongoDB</code> custom resource and let the operator roll the cluster. Don&rsquo;t wait for the June operator release to do it for you. See details in our documentation on how to <a href="https://docs.percona.com/percona-operator-for-mongodb/update-db.html">Upgrade Percona Server for MongoDB</a>.</p>
<p>While you&rsquo;re in there, audit your custom roles. Anything granting <code>createCollection</code> on a production database is, today, an RCE primitive in waiting. Decide whether the service accounts that hold it actually need it. Decide whether your application users need full <code>readWrite</code> or whether a narrower role would do the same job. Treat the answer as part of your security posture, not as a quarterly cleanup task you&rsquo;ll get to.</p>
<p><em>Questions, sharp disagreements, or a 5.x build that won&rsquo;t compile? Find us on the <a href="https://forums.percona.com/">Percona Forum or, if you&rsquo;re a customer, in your support portal. If you want to become one and ensure your databases run, check out </a><a href="https://www.percona.com/services/">Percona Services</a><a href="https://forums.percona.com/">.</a></em></p>
<p>The post <a href="https://www.percona.com/blog/cve-2026-8053-we-dont-use-time-series-is-not-a-mitigation/">CVE-2026-8053: &ldquo;We don&rsquo;t use time-series&rdquo; is not a mitigation</a> appeared first on <a href="https://www.percona.com">Percona</a>.</p>

<p>The post <a rel="nofollow" href="https://www.percona.com/blog/cve-2026-8053-we-dont-use-time-series-is-not-a-mitigation/">CVE-2026-8053: “We don’t use time-series” is not a mitigation</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Not All Open Source Is Equal: Choosing a PostgreSQL Operator for Kubernetes in 2026</title>
      <link>https://www.percona.com/blog/not-all-open-source-is-equal-choosing-postgresql-operator-kubernetes-2026/</link>
      <pubDate>Tue, 19 May 2026 17:12:07 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://www.percona.com/blog/">Blog - Percona</source>
      <description><![CDATA[<p>Choosing an open source PostgreSQL operator for Kubernetes used to be a question about features and community size. In 2026, it has become a question about licensing posture, image distribution, and whether the project you pick today will still be operationally open in three years. This is part 1 of a 3-part series on running … Continued<br />
The post Not All Open Source Is Equal: Choosing a PostgreSQL Operator for Kubernetes in 2026 appeared first on Percona.</p>
<p>The post <a rel="nofollow" href="https://www.percona.com/blog/not-all-open-source-is-equal-choosing-postgresql-operator-kubernetes-2026/">Not All Open Source Is Equal: Choosing a PostgreSQL Operator for Kubernetes in 2026</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p><span style="font-weight: 400"><img decoding="async" loading="lazy" class="aligncenter wp-image-47116 size-large" src="https://www.percona.com/wp-content/uploads/2026/05/hero-2-1024x375.png" alt="" width="1024" height="375"><br>
Choosing an open source PostgreSQL operator for Kubernetes used to be a question about features and community size. In 2026, it has become a question about licensing posture, image distribution, and whether the project you pick today will still be operationally open in three years.</span></p>
<p>This is <b>part 1 of a 3-part series</b><span style="font-weight: 400"> on running PostgreSQL on Kubernetes with a fully open-source operator.</span></p>
<ul>
<li style="font-weight: 400"><b>Part 1 (this post)</b><span style="font-weight: 400">: how the open-source landscape has shifted under your feet, and what to look for in an operator before you commit</span></li>
<li style="font-weight: 400"><b>Part 2</b><span style="font-weight: 400">: migrating from the Crunchy Data PostgreSQL Operator to the Percona PostgreSQL Operator using the standby cluster method (near-zero downtime)</span></li>
<li style="font-weight: 400"><b>Part 3</b><span style="font-weight: 400">: two simpler migration paths: backup-and-restore and persistent-volume reuse</span></li>
</ul>
<p><span style="font-weight: 400">In this post, you will learn about:</span></p>
<ul>
<li style="font-weight: 400"><span style="font-weight: 400">What has changed in the open-source landscape over the last few years, with specific examples</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">What licensing and redistribution actually mean for Kubernetes operators in production</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">How to evaluate whether a project is &ldquo;open source in theory&rdquo; or open source in practice</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Where Percona&rsquo;s PostgreSQL Operator fits in, and what the practical migration looks like</span></li>
</ul>
<p><b>Open source isn&rsquo;t what it used to be</b><b><br>
</b><span style="font-weight: 400">The landscape of open source has undergone significant changes in recent years, and selecting the right operator and tooling for PostgreSQL clusters in Kubernetes has never been more important. Three recent shifts illustrate the pattern.</span></p>
<p>&nbsp;</p>
<h3><b><br>
MinIO</b><a class="anchor-link" id="minio"></a></h3>
<p><span style="font-weight: 400">MinIO was the default open-source S3-compatible storage backend for Kubernetes workloads for years. The trajectory over the last few years tells the story:</span></p>
<ul>
<li style="font-weight: 400"><a href="https://blog.min.io/agplv3-open-source-license/"><span style="font-weight: 400">Switched its license to AGPLv3</span></a><span style="font-weight: 400">, with several enterprise features moved into a commercial-only edition</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Entered what amounted to maintenance mode, narrowing community engagement, limiting support to paid subscriptions, and reducing acceptance of community contributions</span></li>
<li style="font-weight: 400"><b>On April 25, 2026, the </b><a href="https://github.com/minio/minio"><b>github.com/minio/minio</b></a><b> repository was archived by the project owner</b><span style="font-weight: 400">, ending public development of the open-source version</span></li>
</ul>
<p><span style="font-weight: 400">The code is still cloneable, but the project is no longer maintained as open source. Teams running MinIO in production now need an exit plan.</span></p>
<p>&nbsp;</p>
<h3><b>Bitnami images</b><a class="anchor-link" id="bitnami-images"></a></h3>
<p><span style="font-weight: 400">Bitnami Docker images have long been a staple for databases (including Postgres), middleware, and developer tooling. In July 2025, Broadcom&rsquo;s Tanzu Division </span><a href="https://news.broadcom.com/app-dev/broadcom-introduces-bitnami-secure-images-for-production-ready-containerized-applications"><span style="font-weight: 400">announced Bitnami Secure Images</span></a><span style="font-weight: 400"> and </span><a href="https://github.com/bitnami/containers/issues/83267"><span style="font-weight: 400">signalled the deprecation of the free public catalog</span></a><span style="font-weight: 400">. The concrete timeline that followed:</span></p>
<ul>
<li style="font-weight: 400"><b>August 28, 2025</b><span style="font-weight: 400">: deprecation of non-hardened Debian-based images in the free tier began, and non-latest images started to be removed</span></li>
<li style="font-weight: 400"><b>September 29, 2025</b><span style="font-weight: 400"> (after community pushback): the public </span><span style="font-weight: 400">docker.io/bitnami</span><span style="font-weight: 400"> catalog was reduced. The remaining free images were limited to a small curated set of latest-version, hardened images intended for development use; older versions of most applications were moved to a &ldquo;Bitnami Legacy&rdquo; repository</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">The full catalog and the hardened production images now require a paid</span><b> Bitnami Secure Images</b><span style="font-weight: 400"> subscription, </span><a href="https://thenewstack.io/broadcom-ends-free-bitnami-images-forcing-users-to-find-alternatives/"><span style="font-weight: 400">reportedly priced in the tens of thousands of dollars per year</span></a><span style="font-weight: 400"> per organization</span></li>
</ul>
<p><span style="font-weight: 400">For Kubernetes teams, the practical impact was immediate: any Helm chart that pinned a specific Bitnami image version (a recommended practice) found that image gone or moved, breaking CI pipelines and air-gapped deployments.</span></p>
<p>&nbsp;</p>
<h3><b>Crunchy Data PostgreSQL images</b><a class="anchor-link" id="crunchy-data-postgresql-images"></a></h3>
<p><span style="font-weight: 400">Crunchy Data <a href="https://www.percona.com/blog/support-for-crunchy-hardened-postgresql-ends-soon-dont-get-caught-off-guard/">illustrates the same dynamic in the Postgres operator space</a>. To be clear: the Crunchy Data PostgreSQL Operator is a mature, well-engineered project, and the team behind it has done a lot of valuable work upstream and around pgBackRest and Patroni integrations. The point of this section is not the engineering, it is the redistribution and usage terms that govern the official builds.</span></p>
<h3>Crunchy&rsquo;s licensing shifts, 2022 to 2024<a class="anchor-link" id="crunchys-licensing-shifts-2022-to-2024"></a></h3>
<p>Between 2022 and 2024, several shifts occurred:</p>
<ul>
<li style="font-weight: 400"><b>Redistribution restrictions.</b><span style="font-weight: 400"> While the PostgreSQL code is open source, Crunchy&rsquo;s official Docker images include branding and enterprise features that are not freely redistributable. The </span><a href="https://www.crunchydata.com/developers/terms"><span style="font-weight: 400">Crunchy Data Developer Program terms</span></a><span style="font-weight: 400"> describe the software as intended for internal or personal use; production use by larger organizations typically requires an active support subscription.</span></li>
<li style="font-weight: 400"><b>Restrictions on consulting and resale.</b><span style="font-weight: 400"> The terms explicitly prohibit using Crunchy&rsquo;s images to deliver support or consulting services to others without an authorized agreement. The PostgreSQL source code remains open source, but the official images and their packaging are not freely redistributable, which limits practical use in commercial and customer-facing settings.</span></li>
<li style="font-weight: 400"><b>Registry move.</b><span style="font-weight: 400"> Most images were moved to </span><span style="font-weight: 400">registry.developers.crunchydata.com</span><span style="font-weight: 400">, which requires authentication and acceptance of terms before pulling. That draws a clearer line between open-source code and proprietary builds.</span></li>
</ul>
<p><span style="font-weight: 400">In other words, the project is open source on the code side, but the practical artifacts (images, Helm releases) are gated.</span></p>
<p>&nbsp;</p>
<h3><b>What these restrictions really mean for Kubernetes users</b><a class="anchor-link" id="what-these-restrictions-really-mean-for-kubernetes-users"></a></h3>
<p><span style="font-weight: 400">When container images and operators come with redistribution limits, authentication requirements, or &ldquo;internal-use-only&rdquo; clauses, the impact on Kubernetes environments is immediate and concrete. Teams can no longer:</span></p>
<ul>
<li style="font-weight: 400"><span style="font-weight: 400">Build air-gapped clusters by mirroring images to a private registry without working through a license review</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Rely on GitOps workflows that assume publicly accessible OCI images</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Fork or customize the operator freely, because official images cannot be redistributed with modifications</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Use the software in commercial or customer-facing products without additional licensing</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Run multi-cluster or multi-tenant Postgres at scale without bumping into usage terms</span></li>
</ul>
<p><span style="font-weight: 400">For a database operator, where almost every operational pattern depends on the container images you can pull and run, these restrictions effectively turn a project into a &ldquo;source-available but not operationally open&rdquo; solution. The code is open. The operating story is not.</span><br>
<span style="font-weight: 400">As a result, many teams are switching to fully open-source alternatives: the <a href="https://docs.percona.com/percona-operator-for-postgresql/latest/">Percona Operator for PostgreSQL</a>, <a href="https://cloudnative-pg.io/">CloudNativePG</a>, <a href="https://github.com/zalando/postgres-operator">Zalando Postgres Operator</a>, <a href="https://stackgres.io/">StackGres</a>, and a few others.</span></p>
<p>&nbsp;</p>
<h3><b>How to evaluate &ldquo;open source&rdquo; in 2026</b><a class="anchor-link" id="how-to-evaluate-open-source-in-2026"></a></h3>
<p><span style="font-weight: 400">The bigger picture here is that &ldquo;open source&rdquo; today often exists more in theory than in practice. It pays to look past the badge and check the operating reality. Three questions to ask before you commit to an operator:</span></p>
<h4>1. Are the container images publicly redistributable?</h4>
<p><span style="font-weight: 400">If you cannot pull the official images without authentication, or you cannot mirror them to your private registry without a license review, your air-gapped and GitOps stories are constrained from day one. This is the question that turned out to be the most consequential one for MinIO, Bitnami, and Crunchy users in 2025.<br>
</span></p>
<h4>2. Are core operational features in the open-source build, or behind a paywall?</h4>
<p>Backup, monitoring, HA, and security features should be in the build everyone uses, not gated behind an enterprise tier. A &ldquo;community edition&rdquo; that omits the feature most teams actually need is a marketing build, not a real open-source build.</p>
<h4>3. Is the governance and roadmap public?</h4>
<p>A project where you can see the issues, the PRs, and the roadmap is one you can plan around. The Percona PG Operator&rsquo;s&nbsp;<a href="https://github.com/orgs/percona/projects/10/views/6">public roadmap</a>&nbsp;is an example of what this looks like in practice. A project run inside a vendor&rsquo;s private tracker, by contrast, gives you no visibility.<br>
These are not gotchas. They are the questions that decide whether a project will still serve you the same way in three years.</p>
<p>&nbsp;</p>
<h3><b><br>
Migrate to freedom</b><a class="anchor-link" id="migrate-to-freedom"></a></h3>
<h4>Announcing the hard fork</h4>
<p><span style="font-weight: 400">We strongly believe in fully open-source software and want to increase our investment in the PostgreSQL and Kubernetes ecosystems. To back that up, we have decided to </span><b>hard fork the Crunchy Data PostgreSQL Kubernetes Operator</b><span style="font-weight: 400">. Starting from version <strong>3.0.0 (coming soon)</strong>, the Percona PostgreSQL Kubernetes Operator is a <strong>fully independent</strong> project, with a </span><a href="https://github.com/orgs/percona/projects/10/views/6"><span style="font-weight: 400">public roadmap</span></a><span style="font-weight: 400">, public issue tracker, and freely redistributable images.<br>
</span><br>
<span style="font-weight: 400">The hard fork is not a critique of Crunchy&rsquo;s engineering. It is a commitment that the operator will keep evolving in a fully open-source direction, with no surprises about which features will be available to which audience.</span></p>
<h4>Why migration is straightforward</h4>
<p>Because the Percona PostgreSQL Operator is a hard fork of the Crunchy operator, the migration paths are surprisingly straightforward. The same underlying tools (Patroni, pgBackRest, PgBouncer) and the same overall design are used in both, which means migration can be done in multiple ways, sometimes with near-zero downtime, sometimes faster with a small downtime window. The next two posts in this series walk through three concrete options.</p>
<h3><b>What&rsquo;s next</b><a class="anchor-link" id="whats-next"></a></h3>
<p><span style="font-weight: 400">This was the &ldquo;why.&rdquo; The next two posts are the &ldquo;how&rdquo;:</span></p>
<ul>
<li style="font-weight: 400"><b>Part 2: Standby cluster migration.</b><span style="font-weight: 400"> Bring up a Percona cluster as a standby of the Crunchy primary, catch it up via pgBackRest plus streaming replication, and promote it at cutover. The only downtime is the cutover itself.</span></li>
<li style="font-weight: 400"><b>Part 3: Backup-restore and PV reuse.</b><span style="font-weight: 400"> Two simpler paths: bootstrap a Percona cluster directly from a Crunchy pgBackRest backup, or retain the existing PGDATA persistent volume and have Percona pick up where Crunchy left off.</span></li>
</ul>
<h4>Reversibility and exit options</h4>
<p>All three paths are reversible: because Percona&rsquo;s operator, images, and tooling are 100 percent open source and remain compatible with the same backup format and the same Patroni HA model, you keep full control. You can migrate back to Crunchy if your team decides to, or out to another open-source operator (CloudNativePG, Zalando, StackGres) using the same patterns. That last journey is a topic for a future article.</p>
<p><span style="font-weight: 400">This series covers basic deployment patterns and simplified configuration examples. If your environment is more complex, uses custom images, includes Crunchy enterprise features like TDE, or otherwise needs tailored migration steps, contact the Percona team and we will help you plan and execute the move.</span></p>
<p>&nbsp;</p>
<h3><b><br>
Try It Out</b><a class="anchor-link" id="try-it-out"></a></h3>
<ul>
<li style="font-weight: 400"><b>Percona Operator for PostgreSQL docs:</b><a href="https://docs.percona.com/percona-operator-for-postgresql/latest/"> https://docs.percona.com/percona-operator-for-postgresql/latest/</a></li>
<li style="font-weight: 400"><b>GitHub:</b> <a href="https://github.com/percona/percona-postgresql-operator"><span style="font-weight: 400">https://github.com/percona/percona-postgresql-operator</span></a></li>
<li style="font-weight: 400"><b>Public roadmap:</b> <a href="https://github.com/orgs/percona/projects/10/views/6"><span style="font-weight: 400">https://github.com/orgs/percona/projects/10/views/6</span></a></li>
<li style="font-weight: 400"><b>Issue tracker: </b><a href="https://github.com/percona/percona-postgresql-operator/issues"><span style="font-weight: 400">https://github.com/percona/percona-postgresql-operator/issues</span></a></li>
<li style="font-weight: 400"><b>Community Forum: </b><a href="https://forums.percona.com/c/postgresql/percona-kubernetes-operator-for-postgresql/68">https://forums.percona.com/c/postgresql/percona-kubernetes-operator-for-postgresql/68</a></li>
</ul>
<p>The post <a href="https://www.percona.com/blog/not-all-open-source-is-equal-choosing-postgresql-operator-kubernetes-2026/">Not All Open Source Is Equal: Choosing a PostgreSQL Operator for Kubernetes in 2026</a> appeared first on <a href="https://www.percona.com">Percona</a>.</p>

<p>The post <a rel="nofollow" href="https://www.percona.com/blog/not-all-open-source-is-equal-choosing-postgresql-operator-kubernetes-2026/">Not All Open Source Is Equal: Choosing a PostgreSQL Operator for Kubernetes in 2026</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Backrest&#8217;s back, alright!</title>
      <link>https://percona.community/blog/2026/05/19/backrests-back-alright/</link>
      <pubDate>Tue, 19 May 2026 11:00:00 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://percona.community/blog/">Percona Community Blog - learn about MySQL, MariaDB, PostgreSQL, and MongoDB</source>
      <description><![CDATA[<p>Events unfolded quickly over the course of a couple of weeks starting on 27 April 2026, when a message appeared on the pgBackRest project announcing: that the repository would be archived and active maintenance would stop.</p>
<p>The post <a rel="nofollow" href="https://percona.community/blog/2026/05/19/backrests-back-alright/">Backrest&#8217;s back, alright!</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>Events unfolded quickly over the course of a couple of weeks starting on 27 April 2026, when a <a href="https://pgbackrest.org/news.html" target="_blank" rel="noopener noreferrer">message appeared on the pgBackRest project announcing</a>:<br>
that the repository would be archived and active maintenance would stop.</p>
<p><figure>
<img decoding="async" src="https://percona.community/blog/2026/05/Jan-pgb-news-1.png" alt="blog/2026/05/Jan-pgb-news-1.png"></figure>
</p>
<p>For many in the PostgreSQL ecosystem, this landed like a shock. <a href="https://pgbackrest.org/" target="_blank" rel="noopener noreferrer">pgBackRest</a> is one of the most widely used backup and recovery tools for PostgreSQL, deeply embedded in production environments across enterprises large and small. Now it was suddenly described as &ldquo;<a href="https://mydbanotebook.org/posts/pgbackrest-is-dead.-now-what/" target="_blank" rel="noopener noreferrer">dead</a>&rdquo;, &ldquo;<a href="https://www.gabrielebartolini.it/articles/2026/04/why-the-cycle-of-open-source-sustainability-needs-to-be-virtuous/" target="_blank" rel="noopener noreferrer">EOL</a>&rdquo;, or &ldquo;<a href="https://news.ycombinator.com/item?id=47919997" target="_blank" rel="noopener noreferrer">abandoned</a>&rdquo;. The trigger was clear: its long-time maintainer, after more than a decade of work, announced he could no longer continue without sustainable funding and would archive the repository.<br>
i<br>
That message spread fast. The interpretation spread even faster.</p>
<p>And it was wrong.</p>
<h2 id="this-wasnt-eol">This wasn&rsquo;t EOL<a class="anchor-link" id="this-wasnt-eol"></a></h2>
<p>Open source software doesn&rsquo;t simply &ldquo;go end of life&rdquo; in the way proprietary software does. There is no vendor switch flipped to OFF. No license revoked. No binaries disappearing overnight.</p>
<p>What actually happens is more subtle and more important:</p>
<ul>
<li>Maintainers step away</li>
<li>Funding runs out</li>
<li>Work stops</li>
</ul>
<p>That&rsquo;s not EOL. That&rsquo;s a sustainability gap.</p>
<p><a href="https://github.com/pgbackrest/pgbackrest" target="_blank" rel="noopener noreferrer">pgBackRest</a> didn&rsquo;t die. It hit a problem seen too often in open source world: a critical piece of infrastructure maintained by fewer and fewer people, until it ultimately depended on one person being able to justify working on it full time.</p>
<h2 id="the-real-problem">The real problem<a class="anchor-link" id="the-real-problem"></a></h2>
<p>The message from the maintainer was not about abandoning the project. It was about reality:</p>
<blockquote>
<p>maintaining a widely used tool requires time, and time requires funding</p>
</blockquote>
<p>For years, pgBackRest was supported through corporate sponsorship from mainly one vendor. When that disappeared due to the Crunchy Data acquisition, so did the ability to keep investing the same level of effort.</p>
<p>This is the &ldquo;<a href="https://xkcd.com/2347/" target="_blank" rel="noopener noreferrer">Nebraska guy problem</a>&rdquo; in action: software used by a large part of the industry, sustained by a very small number of people.</p>
<p>Yes, anyone can fork the project (and some already did), but:</p>
<ul>
<li>trust doesn&rsquo;t fork</li>
<li>community doesn&rsquo;t fork</li>
<li>sustainability definitely doesn&rsquo;t fork</li>
</ul>
<p>A fork without coordination creates fragmentation without adding real value and that weakens the ecosystem. What pgBackRest needed was not a replacement, but continuity.</p>
<h2 id="the-danger-of-bad-framing">The danger of bad framing<a class="anchor-link" id="the-danger-of-bad-framing"></a></h2>
<p>Calling the project &ldquo;dead&rdquo; shifted the conversation in the wrong direction.</p>
<p><figure>
<img decoding="async" src="https://percona.community/blog/2026/05/Jan-pgb-not-dead.png" alt="blog/2026/05/Jan-pgb-not-dead.png"></figure>
</p>
<p>Instead of asking:</p>
<blockquote>
<p>how do we keep this project healthy?</p>
</blockquote>
<p>the discussion drifted at best toward:</p>
<blockquote>
<p>what is the strategic solution here?</p>
</blockquote>
<p>and more often to:</p>
<blockquote>
<p>what do we replace it with?</p>
</blockquote>
<p>and</p>
<blockquote>
<p>what do we name our fork?</p>
</blockquote>
<p>That&rsquo;s a natural reaction, but it&rsquo;s not a good one.</p>
<p>Critical infrastructure should not be treated as disposable. Doing so erodes trust in the solutions we rely on and weakens the ecosystem. These foundational pieces should be treated as a shared responsibility so that the entire community becomes stronger.</p>
<h2 id="what-happened-next">What happened next<a class="anchor-link" id="what-happened-next"></a></h2>
<p>Behind the scenes, things moved quickly, with coordination between David and companies active in the PostgreSQL community.</p>
<p><figure>
<img decoding="async" src="https://percona.community/blog/2026/05/Jan-pgb-news-2.png" alt="blog/2026/05/Jan-pgb-news-2.png"></figure>
</p>
<p>Conversations started across companies, contributors and the wider ecosystem. The goal wasn&rsquo;t to &ldquo;rescue&rdquo; pgBackRest, but to do something far more valuable: to restore a sustainable model around it.</p>
<p>This is what open source actually requires: not heroics, but coordination.</p>
<h2 id="so-whats-with-pgbackrest">So what&rsquo;s with pgBackRest?<a class="anchor-link" id="so-whats-with-pgbackrest"></a></h2>
<p>It&rsquo;s all good. Well, better.</p>

<p>The short version:</p>
<ul>
<li><a href="https://pgbackrest.org/news.html#will-continue" target="_blank" rel="noopener noreferrer">Multiple companies coordinated together</a> to <a href="https://www.globenewswire.com/news-release/2026/05/19/3297383/0/en/open-source-stays-open-percona-sponsors-pgbackrest-to-keep-postgresql-backups-running.html" target="_blank" rel="noopener noreferrer">ensure continued funding and support around pgBackRest</a></li>
<li>Engineering effort is now being shared more broadly to expand the contributor and maintainer base</li>
<li>Discussions around longer term sustainability and governance in the PostgreSQL ecosystem accelerated significantly</li>
<li><strong>Percona</strong> played an active role in coordinating these efforts, contributing engineering resources, and helping bring organizations together around a sustainable path forward</li>
</ul>
<p><figure>
<img decoding="async" src="https://percona.community/blog/2026/05/Jan-pgb-news-3.png" alt="blog/2026/05/Jan-pgb-news-3.png"></figure>
</p>
<p>The project was never closed.</p>
<h2 id="the-way-forward-is-open">The way (forward) is open<a class="anchor-link" id="the-way-forward-is-open"></a></h2>
<p>pgBackRest&rsquo;s situation is not unique. It&rsquo;s a signal.</p>
<p><figure>
<img decoding="async" src="https://percona.community/blog/2026/05/Jan-pgb-back.png" alt="blog/2026/05/Jan-pgb-back.png"></figure>
</p>
<p>The PostgreSQL ecosystem depends on a wide range of tools that don&rsquo;t have the same visibility, or funding, as the database itself. That gap is becoming harder to ignore.</p>
<p>There&rsquo;s growing alignment on a few things:</p>
<ul>
<li>sustainability needs to be intentional</li>
<li>funding needs to be easier to organize</li>
<li>engineering effort needs to be shared</li>
</ul>
<p>Whether that leads to an umbrella foundation or another model, one thing is clear: the ecosystem needs structures that support both users and maintainers.</p>

<p>The post <a rel="nofollow" href="https://percona.community/blog/2026/05/19/backrests-back-alright/">Backrest&#8217;s back, alright!</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>MariaDB Community Server Q2 2026 maintenance releases</title>
      <link>https://mariadb.com/resources/blog/mariadb-community-server-q2-2026-maintenance-releases/</link>
      <pubDate>Mon, 18 May 2026 21:10:41 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.com/">MariaDB</source>
      <description><![CDATA[<p>MariaDB is pleased to announce the immediate availability of MariaDB Community Server 11.8.7, 11.4.11, 10.11.17, and 10.6.26 maintenance releases. See […]</p>
<p>The post <a rel="nofollow" href="https://mariadb.com/resources/blog/mariadb-community-server-q2-2026-maintenance-releases/">MariaDB Community Server Q2 2026 maintenance releases</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>MariaDB is pleased to announce the immediate availability of MariaDB Community Server 11.8.7, 11.4.11, 10.11.17, and 10.6.26 maintenance releases. See the release notes and changelogs for additional details on each release and visit mariadb.com/downloads to download.</p>
<p><a href="https://mariadb.com/resources/blog/mariadb-community-server-q2-2026-maintenance-releases/" rel="nofollow">Source</a></p>

<p>The post <a rel="nofollow" href="https://mariadb.com/resources/blog/mariadb-community-server-q2-2026-maintenance-releases/">MariaDB Community Server Q2 2026 maintenance releases</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Introducing Our First MariaDB Server Solution Stack: A Privacy-First Stack with Nextcloud, Passbolt, and MariaDB</title>
      <link>https://mariadb.org/introducing-our-first-mariadb-server-solution-stack-a-privacy-first-stack-with-nextcloud-passbolt-and-mariadb/</link>
      <pubDate>Fri, 15 May 2026 14:27:49 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.org/">MariaDB.org</source>
      <description><![CDATA[<p>MariaDB Foundation is pleased to announce the publication of our first MariaDB Server Solution Stack in the MariaDB Server Ecosystem Hub:<br />
Privacy-First Stack: Nextcloud, Passbolt, and MariaDB Server<br />
This stack brings together three open-source technologies with a shared purpose: helping organizations build collaboration infrastructure around privacy, control, and long-term digital sovereignty. …<br />
Continue reading \"Introducing Our First MariaDB Server Solution Stack: A Privacy-First Stack with Nextcloud, Passbolt, and MariaDB\"<br />
The post Introducing Our First MariaDB Server Solution Stack: A Privacy-First Stack with Nextcloud, Passbolt, and MariaDB appeared first on MariaDB.org.</p>
<p>The post <a rel="nofollow" href="https://mariadb.org/introducing-our-first-mariadb-server-solution-stack-a-privacy-first-stack-with-nextcloud-passbolt-and-mariadb/">Introducing Our First MariaDB Server Solution Stack: A Privacy-First Stack with Nextcloud, Passbolt, and MariaDB</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>MariaDB Foundation is pleased to announce the publication of our first MariaDB Server Solution Stack in the MariaDB Server Ecosystem Hub:<br>
<a href="https://ecohub.mariadb.org/stacks/privacy-first-stack?utm_source=chatgpt.com">Privacy-First Stack: Nextcloud, Passbolt, and MariaDB Server</a><br>
This stack brings together three open-source technologies with a shared purpose: helping organizations build collaboration infrastructure around privacy, control, and long-term digital sovereignty. &hellip; </p>
<p class="link-more"><a href="https://mariadb.org/introducing-our-first-mariadb-server-solution-stack-a-privacy-first-stack-with-nextcloud-passbolt-and-mariadb/" class="more-link">Continue reading<span class="screen-reader-text"> &ldquo;Introducing Our First MariaDB Server Solution Stack: A Privacy-First Stack with Nextcloud, Passbolt, and MariaDB&rdquo;</span></a></p>
<p>The post <a rel="nofollow" href="https://mariadb.org/introducing-our-first-mariadb-server-solution-stack-a-privacy-first-stack-with-nextcloud-passbolt-and-mariadb/">Introducing Our First MariaDB Server Solution Stack: A Privacy-First Stack with Nextcloud, Passbolt, and MariaDB</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>

<p>The post <a rel="nofollow" href="https://mariadb.org/introducing-our-first-mariadb-server-solution-stack-a-privacy-first-stack-with-nextcloud-passbolt-and-mariadb/">Introducing Our First MariaDB Server Solution Stack: A Privacy-First Stack with Nextcloud, Passbolt, and MariaDB</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>MariaDB Community Server 10.6 Is Reaching End of Life – Here’s What to Do Next</title>
      <link>https://mariadb.com/resources/blog/mariadb-community-server-10-6-is-reaching-end-of-life-heres-what-to-do-next/</link>
      <pubDate>Thu, 14 May 2026 17:21:52 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.com/">MariaDB</source>
      <description><![CDATA[<p>If you’re running MariaDB Community Server 10.6, mark your calendar: July 6, 2026 is the official End of Life (EOL) […]</p>
<p>The post <a rel="nofollow" href="https://mariadb.com/resources/blog/mariadb-community-server-10-6-is-reaching-end-of-life-heres-what-to-do-next/">MariaDB Community Server 10.6 Is Reaching End of Life – Here’s What to Do Next</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>If you&rsquo;re running MariaDB Community Server 10.6, mark your calendar: July 6, 2026 is the official End of Life (EOL) date. After that date, there will no longer be security patches, bug fixes, or updates for this version. That&rsquo;s not a distant concern &ndash; it&rsquo;s a few weeks away. And if you haven&rsquo;t started planning your next move, now is the time. This post walks you through what EOL actually&hellip;</p>
<p><a href="https://mariadb.com/resources/blog/mariadb-community-server-10-6-is-reaching-end-of-life-heres-what-to-do-next/" rel="nofollow">Source</a></p>

<p>The post <a rel="nofollow" href="https://mariadb.com/resources/blog/mariadb-community-server-10-6-is-reaching-end-of-life-heres-what-to-do-next/">MariaDB Community Server 10.6 Is Reaching End of Life – Here’s What to Do Next</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Documented: The MariaDB Server (Community) Contribution Process</title>
      <link>https://mariadb.org/documented-the-mariadb-server-community-contribution-process/</link>
      <pubDate>Mon, 11 May 2026 14:13:34 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.org/">MariaDB.org</source>
      <description><![CDATA[<p>If you ever considered contributing code to the MariaDB server, you should know that this is an intricate process involving multiple steps and multiple actors. To help you see your contributions successfully merged into the MariaDB Server codebase I’ve compiled a comprehensive description of the contribution process itself, the roles involved into it, the sequence of actions and conditions for transition from one to another. …<br />
Continue reading \"Documented: The MariaDB Server (Community) Contribution Process\"<br />
The post Documented: The MariaDB Server (Community) Contribution Process appeared first on MariaDB.org.</p>
<p>The post <a rel="nofollow" href="https://mariadb.org/documented-the-mariadb-server-community-contribution-process/">Documented: The MariaDB Server (Community) Contribution Process</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>If you ever considered contributing code to the MariaDB server, you should know that this is an intricate process involving multiple steps and multiple actors. To help you see your contributions successfully merged into the MariaDB Server <a href="https://github.com/MariaDB/server/">codebase</a> I&rsquo;ve compiled a comprehensive description of the contribution process itself, the roles involved into it, the sequence of actions and conditions for transition from one to another. &hellip; </p>
<p class="link-more"><a href="https://mariadb.org/documented-the-mariadb-server-community-contribution-process/" class="more-link">Continue reading<span class="screen-reader-text"> &ldquo;Documented: The MariaDB Server (Community) Contribution Process&rdquo;</span></a></p>
<p>The post <a rel="nofollow" href="https://mariadb.org/documented-the-mariadb-server-community-contribution-process/">Documented: The MariaDB Server (Community) Contribution Process</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>

<p>The post <a rel="nofollow" href="https://mariadb.org/documented-the-mariadb-server-community-contribution-process/">Documented: The MariaDB Server (Community) Contribution Process</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Our Experience at MongoDB.local London 2026: The Era of AI Agents, Badges, and&#8230; Surviving on Chips!</title>
      <link>https://percona.community/blog/2026/05/11/our-experience-at-mongodb.local-london-2026-the-era-of-ai-agents-badges-and...-surviving-on-chips/</link>
      <pubDate>Mon, 11 May 2026 00:00:00 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://percona.community/blog/">Percona Community Blog - learn about MySQL, MariaDB, PostgreSQL, and MongoDB</source>
      <description><![CDATA[<p>On May 7th, Keith (Quality Engineer, Percona for MongoDB) and I had the super cool opportunity to head over to MongoDB.local London! The event was amazing and packed with insights about where the database ecosystem is heading.</p>
<p>The post <a rel="nofollow" href="https://percona.community/blog/2026/05/11/our-experience-at-mongodb.local-london-2026-the-era-of-ai-agents-badges-and...-surviving-on-chips/">Our Experience at MongoDB.local London 2026: The Era of AI Agents, Badges, and&#8230; Surviving on Chips!</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>On May 7th, <strong>Keith</strong> (Quality Engineer, Percona for MongoDB) and I had the super cool opportunity to head over to <a href="https://www.mongodb.com/events/mongodb-local/london" target="_blank" rel="noopener noreferrer">MongoDB.local London</a>! The event was amazing and packed with insights about where the database ecosystem is heading.</p>
<p>If there was one massive takeaway from the day, it was this: <strong>We are officially in the Era of AI and &ldquo;Agentic&rdquo; Systems.</strong> During the event, the message was clear: we are shifting from basic LLMs (that just answer a prompt and forget it) to autonomous AI Agents that follow a continuous loop of Perception &rarr; Planning &rarr; Action. MongoDB&rsquo;s President and CEO, CJ Desai, repeated a powerful phrase:</p>
<blockquote>
<p>While AI models change rapidly, the Data Layer is the constant.</p>
</blockquote>
<p><figure><img decoding="async" src="https://percona.community/blog/2026/05/mongodb-desai.png" alt="ceo"></figure>
</p>
<p>Here is a look at our day, what we learned, and the fun we had along the way!</p>
<p><figure><img decoding="async" src="https://percona.community/blog/2026/05/mongodb-team.png" alt="team"></figure>
</p>
<h3 id="arriving-early-and-chasing-badges">Arriving Early and Chasing Badges<a class="anchor-link" id="arriving-early-and-chasing-badges"></a></h3>
<p>We got a great tip before the event: arrive early to get a head start on the gamified learning! MongoDB had a super nice setup where you could take tests on Credly to earn knowledge badges.</p>
<p>We jumped right in. I got a <strong>MongoDB Overview badge</strong>, but Keith was on a mission. He completed three different tests (including MongoDB for Developers) and unlocked some cool swag: a really cute, high-quality bag! It was a brilliant way to get attendees engaged right from the morning.</p>
<p><figure><img decoding="async" src="https://percona.community/blog/2026/05/mongodb-skills.png" alt="skills"></figure>
</p>
<p><a href="https://www.credly.com/organizations/mongodb/collections/mongodb-skill-badges/badge_templates" target="_blank" rel="noopener noreferrer">Here</a> are more badges in case you want to get yours!</p>
<p><figure><img decoding="async" src="https://percona.community/blog/2026/05/mongodb-badges.png" alt="badges"></figure>
</p>
<h3 id="general-session-highlights">General Session Highlights<a class="anchor-link" id="general-session-highlights"></a></h3>
<p>We spent a lot of our time in the main room for the General Session, and the announcements were packed with impressive numbers and tech:</p>
<ul>
<li><strong>MongoDB 8.3 is Fast:</strong> Osmar Olivo (Senior Director, Database Product Management) shared that the new version brings up to 35% more write throughput, 45% more read throughput, and 15% more for ACID transactions.</li>
<li><strong>The Scale is Real:</strong> We learned that Stripe uses MongoDB to process over $1 trillion in payments volume every year (maintaining 5 nines of availability!). Osmar framed this perfectly: that is 1.5% of the global GDP running through MongoDB.</li>
<li><strong>LangGraph.js Store Integration:</strong> This was a big one for developers. MongoDB is positioning itself as the &ldquo;memory hard drive&rdquo; for AI agents. By supporting JavaScript and TypeScript, they are making it super easy for companies to use their existing web developers to build complex AI workflows.</li>
<li><strong>Hugging Face Partnership:</strong> They are scaling with MongoDB Atlas to support over 3 million models, officially tying themselves to the &ldquo;GitHub for AI.&rdquo;</li>
</ul>
<p>Feel free to explore the recorded sessions for more: <a href="https://www.youtube.com/watch?v=mHOQWeuoreM&amp;t=1877s" target="_blank" rel="noopener noreferrer">MongoDB.local London 2026</a></p>
<h3 id="guest-speakers">Guest Speakers<a class="anchor-link" id="guest-speakers"></a></h3>
<p><strong>Ulku Rowe</strong> (CIO, Commercial Business at Lloyds Banking Group) talked about this being the &ldquo;Decade of AI.&rdquo; Lloyds is actively upskilling their current engineers through an internal &ldquo;AI Academy&rdquo; built in partnership with Cambridge University! She emphasized that as they build out this infrastructure, partnerships are absolutely critical to their success.</p>
<p>We also heard from <strong>Alex Holt</strong> from ElevenLabs, a company focused on producing the absolute best, human-sounding voice AI. Their scale is wild: they have 40 million agents running and hit $500 million in Annual Recurring Revenue in just 3 years! Alex mentioned that because many enterprises don&rsquo;t know how to build agents yet, ElevenLabs uses &ldquo;forward deployed engineers&rdquo; to sit directly with customers to build, deploy, and prove the ROI of their voice agents.</p>
<p><figure><img decoding="async" src="https://percona.community/blog/2026/05/mongodb-eleven.png" alt="eleven"></figure>
</p>
<h3 id="the-hands-on-workshop-and-our-lunch-diet">The Hands-on Workshop and Our Lunch &ldquo;Diet&rdquo;<a class="anchor-link" id="the-hands-on-workshop-and-our-lunch-diet"></a></h3>
<p>Later in the day, we attended a hands-on workshop: <strong>Designing Memory Systems for AI Agents</strong>, hands-on workshop about how AI agents can remember information and use it later to give better responses. We used Python and MongoDB Atlas to build memory into an AI agent and learned how to store, search, update, and manage that memory.<br>
The setup was good, everything was prepared in advance so we could focus on executing the commands and truly understanding the concepts. At the end, we answered some questions and earned another badge!</p>
<p><figure><img decoding="async" src="https://percona.community/blog/2026/05/mongodb-workshop.png" alt="badges"></figure>
</p>
<p>However, the workshop ran until 1:00 PM. One of our friends had warned us to &ldquo;go for food fast,&rdquo; but we were too focused on the workshop! By the time we made it to the lunch area, all the main food was completely sold out.</p>
<p><strong>How did we survive?</strong> Chips, candies, and a lot of beverages. Between the sodas, coffee, and tea, we kept our energy, but it was definitely a funny learning experience for next time! I can imagine Keith arriving home for dinner!!</p>
<p><figure><img decoding="async" src="https://percona.community/blog/2026/05/mongodb-gif.gif" alt="badges"></figure>
</p>
<h3 id="exploring-the-sponsor-hall-and-doing-a-podcast">Exploring the Sponsor Hall (And Doing a Podcast!)<a class="anchor-link" id="exploring-the-sponsor-hall-and-doing-a-podcast"></a></h3>
<p>We spent our afternoon speaking with sponsors and even got to participate in a quick podcast focusing on AI and how Atlas is being used as a strong platform for these projects!</p>
<p><figure><img decoding="async" src="https://percona.community/blog/2026/05/mongodb-podcast.png" alt="podcast"></figure>
</p>
<p>The person being interviewed was <strong>Bikram Das</strong>, who is Chief Data Architect at Tata Consulting Services, and we had a great chat with him. TCS and MongoDB have partnered on a super impressive real-time payment and fraud detection platform. They use autonomous AI agents to instantly assess risk, investigate anomalies, and route safe transactions to networks like Visa and SWIFT without any downtime.</p>
<p>We also talked with IBM folks; they showed us their &ldquo;plug-and-play&rdquo; enterprise AI foundation. They are focused on letting large companies safely deploy AI agents without having to completely rip out and rebuild their current data infrastructure.</p>
<p>We also stopped by the Accenture booth! They are actively working on integrating AI directly into their platforms so they can offer smarter, more advanced solutions to their customers.</p>
<h3 id="wrapping-up">Wrapping Up!<a class="anchor-link" id="wrapping-up"></a></h3>
<p>To cap off a great day, MongoDB had one last treat. If you took less than 3 minutes to fill out the end-of-event survey, they handed you a super nice pair of socks. <em>(We love community ideas like this!)</em>.</p>
<p><figure><img decoding="async" src="https://percona.community/blog/2026/05/mongodb-socks.png" alt="podcast"></figure>
</p>
<p>Overall, <strong>MongoDB.local London</strong> was a great experience. It was a nice space to learn, connect, have hands-on experience, and see exactly how the database world is evolving to meet the Agentic AI era head-on.</p>
<p>See you at the next event!</p>
<p><figure><img decoding="async" src="https://percona.community/blog/2026/05/mongodb-percona.png" alt="bye"></figure></p>

<p>The post <a rel="nofollow" href="https://percona.community/blog/2026/05/11/our-experience-at-mongodb.local-london-2026-the-era-of-ai-agents-badges-and...-surviving-on-chips/">Our Experience at MongoDB.local London 2026: The Era of AI Agents, Badges, and&#8230; Surviving on Chips!</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Our Experience at MongoDB.local London 2026: The Era of AI Agents, Badges, and Surviving on Chips!</title>
      <link>https://percona.community/blog/2026/05/11/our-experience-at-mongodb.local-london-2026-the-era-of-ai-agents-badges-and-surviving-on-chips/</link>
      <pubDate>Mon, 11 May 2026 00:00:00 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://percona.community/blog/">Percona Community Blog - learn about MySQL, MariaDB, PostgreSQL, and MongoDB</source>
      <description><![CDATA[<p>On May 7th, Keith (Quality Engineer, Percona for MongoDB) and I had the super cool opportunity to head over to MongoDB.local London! The event was amazing and packed with insights about where the database ecosystem is heading.</p>
<p>The post <a rel="nofollow" href="https://percona.community/blog/2026/05/11/our-experience-at-mongodb.local-london-2026-the-era-of-ai-agents-badges-and-surviving-on-chips/">Our Experience at MongoDB.local London 2026: The Era of AI Agents, Badges, and Surviving on Chips!</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>On May 7th, <strong>Keith</strong> (Quality Engineer, Percona for MongoDB) and I had the super cool opportunity to head over to <a href="https://www.mongodb.com/events/mongodb-local/london" target="_blank" rel="noopener noreferrer">MongoDB.local London</a>! The event was amazing and packed with insights about where the database ecosystem is heading.</p>
<p>If there was one massive takeaway from the day, it was this: <strong>We are officially in the Era of AI and &ldquo;Agentic&rdquo; Systems.</strong> During the event, the message was clear: we are shifting from basic LLMs (that just answer a prompt and forget it) to autonomous AI Agents that follow a continuous loop of Perception &rarr; Planning &rarr; Action. MongoDB&rsquo;s President and CEO, CJ Desai, repeated a powerful phrase:</p>
<blockquote>
<p>While AI models change rapidly, the Data Layer is the constant.</p>
</blockquote>
<p><figure><img decoding="async" src="https://percona.community/blog/2026/05/mongodb-desai.png" alt="ceo"></figure>
</p>
<p>Here is a look at our day, what we learned, and the fun we had along the way!</p>
<p><figure><img decoding="async" src="https://percona.community/blog/2026/05/mongodb-team.png" alt="team"></figure>
</p>
<h3 id="arriving-early-and-chasing-badges">Arriving Early and Chasing Badges<a class="anchor-link" id="arriving-early-and-chasing-badges"></a></h3>
<p>We got a great tip before the event: arrive early to get a head start on the gamified learning! MongoDB had a super nice setup where you could take tests on Credly to earn knowledge badges.</p>
<p>We jumped right in. I got a <strong>MongoDB Overview badge</strong>, but Keith was on a mission. He completed three different tests (including MongoDB for Developers) and unlocked some cool swag: a really cute, high-quality bag! It was a brilliant way to get attendees engaged right from the morning.</p>
<p><figure><img decoding="async" src="https://percona.community/blog/2026/05/mongodb-skills.png" alt="skills"></figure>
</p>
<p><a href="https://www.credly.com/organizations/mongodb/collections/mongodb-skill-badges/badge_templates" target="_blank" rel="noopener noreferrer">Here</a> are more badges in case you want to get yours!</p>
<p><figure><img decoding="async" src="https://percona.community/blog/2026/05/mongodb-badges.png" alt="badges"></figure>
</p>
<h3 id="general-session-highlights">General Session Highlights<a class="anchor-link" id="general-session-highlights"></a></h3>
<p>We spent a lot of our time in the main room for the General Session, and the announcements were packed with impressive numbers and tech:</p>
<ul>
<li><strong>MongoDB 8.3 is Fast:</strong> Osmar Olivo (Senior Director, Database Product Management) shared that the new version brings up to 35% more write throughput, 45% more read throughput, and 15% more for ACID transactions.</li>
<li><strong>The Scale is Real:</strong> We learned that Stripe uses MongoDB to process over $1 trillion in payments volume every year (maintaining 5 nines of availability!). Osmar framed this perfectly: that is 1.5% of the global GDP running through MongoDB.</li>
<li><strong>LangGraph.js Store Integration:</strong> This was a big one for developers. MongoDB is positioning itself as the &ldquo;memory hard drive&rdquo; for AI agents. By supporting JavaScript and TypeScript, they are making it super easy for companies to use their existing web developers to build complex AI workflows.</li>
<li><strong>Hugging Face Partnership:</strong> They are scaling with MongoDB Atlas to support over 3 million models, officially tying themselves to the &ldquo;GitHub for AI.&rdquo;</li>
</ul>
<p>Feel free to explore the recorded sessions for more: <a href="https://www.youtube.com/watch?v=mHOQWeuoreM&amp;t=1877s" target="_blank" rel="noopener noreferrer">MongoDB.local London 2026</a></p>
<h3 id="guest-speakers">Guest Speakers<a class="anchor-link" id="guest-speakers"></a></h3>
<p><strong>Ulku Rowe</strong> (CIO, Commercial Business at Lloyds Banking Group) talked about this being the &ldquo;Decade of AI.&rdquo; Lloyds is actively upskilling their current engineers through an internal &ldquo;AI Academy&rdquo; built in partnership with Cambridge University! She emphasized that as they build out this infrastructure, partnerships are absolutely critical to their success.</p>
<p>We also heard from <strong>Alex Holt</strong> from ElevenLabs, a company focused on producing the absolute best, human-sounding voice AI. Their scale is wild: they have 40 million agents running and hit $500 million in Annual Recurring Revenue in just 3 years! Alex mentioned that because many enterprises don&rsquo;t know how to build agents yet, ElevenLabs uses &ldquo;forward deployed engineers&rdquo; to sit directly with customers to build, deploy, and prove the ROI of their voice agents.</p>
<p><figure><img decoding="async" src="https://percona.community/blog/2026/05/mongodb-eleven.png" alt="eleven"></figure>
</p>
<h3 id="the-hands-on-workshop-and-our-lunch-diet">The Hands-on Workshop and Our Lunch &ldquo;Diet&rdquo;<a class="anchor-link" id="the-hands-on-workshop-and-our-lunch-diet"></a></h3>
<p>Later in the day, we attended a hands-on workshop: <strong>Designing Memory Systems for AI Agents</strong>, hands-on workshop about how AI agents can remember information and use it later to give better responses. We used Python and MongoDB Atlas to build memory into an AI agent and learned how to store, search, update, and manage that memory.<br>
The setup was good, everything was prepared in advance so we could focus on executing the commands and truly understanding the concepts. At the end, we answered some questions and earned another badge!</p>
<p><figure><img decoding="async" src="https://percona.community/blog/2026/05/mongodb-workshop.png" alt="badges"></figure>
</p>
<p>However, the workshop ran until 1:00 PM. One of our friends had warned us to &ldquo;go for food fast,&rdquo; but we were too focused on the workshop! By the time we made it to the lunch area, all the main food was completely sold out.</p>
<p><strong>How did we survive?</strong> Chips, candies, and a lot of beverages. Between the sodas, coffee, and tea, we kept our energy, but it was definitely a funny learning experience for next time! I can imagine Keith arriving home for dinner!!</p>
<p><figure><img decoding="async" src="https://percona.community/blog/2026/05/mongodb-gif.gif" alt="badges"></figure>
</p>
<h3 id="exploring-the-sponsor-hall-and-doing-a-podcast">Exploring the Sponsor Hall (And Doing a Podcast!)<a class="anchor-link" id="exploring-the-sponsor-hall-and-doing-a-podcast"></a></h3>
<p>We spent our afternoon speaking with sponsors and even got to participate in a quick podcast focusing on AI and how Atlas is being used as a strong platform for these projects!</p>
<p><figure><img decoding="async" src="https://percona.community/blog/2026/05/mongodb-podcast.png" alt="podcast"></figure>
</p>
<p>The person being interviewed was <strong>Bikram Das</strong>, who is Chief Data Architect at Tata Consulting Services, and we had a great chat with him. TCS and MongoDB have partnered on a super impressive real-time payment and fraud detection platform. They use autonomous AI agents to instantly assess risk, investigate anomalies, and route safe transactions to networks like Visa and SWIFT without any downtime.</p>
<p>We also talked with IBM folks; they showed us their &ldquo;plug-and-play&rdquo; enterprise AI foundation. They are focused on letting large companies safely deploy AI agents without having to completely rip out and rebuild their current data infrastructure.</p>
<p>We also stopped by the Accenture booth! They are actively working on integrating AI directly into their platforms so they can offer smarter, more advanced solutions to their customers.</p>
<h3 id="wrapping-up">Wrapping Up!<a class="anchor-link" id="wrapping-up"></a></h3>
<p>To cap off a great day, MongoDB had one last treat. If you took less than 3 minutes to fill out the end-of-event survey, they handed you a super nice pair of socks. <em>(We love community ideas like this!)</em>.</p>
<p><figure><img decoding="async" src="https://percona.community/blog/2026/05/mongodb-socks.png" alt="podcast"></figure>
</p>
<p>Overall, <strong>MongoDB.local London</strong> was a great experience. It was a nice space to learn, connect, have hands-on experience, and see exactly how the database world is evolving to meet the Agentic AI era head-on.</p>
<p>See you at the next event!</p>
<p><figure><img decoding="async" src="https://percona.community/blog/2026/05/mongodb-percona.png" alt="bye"></figure></p>

<p>The post <a rel="nofollow" href="https://percona.community/blog/2026/05/11/our-experience-at-mongodb.local-london-2026-the-era-of-ai-agents-badges-and-surviving-on-chips/">Our Experience at MongoDB.local London 2026: The Era of AI Agents, Badges, and Surviving on Chips!</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Unleashing Innovation Through Plugins</title>
      <link>https://mariadb.org/unleashing-innovation-through-plugins/</link>
      <pubDate>Fri, 08 May 2026 09:23:58 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.org/">MariaDB.org</source>
      <description><![CDATA[<p>One of the corner stones in MariaDB Foundation’s mission is:<br />
We strive to increase adoption by users and across use cases, platforms and means of deployment. …<br />
Continue reading \"Unleashing Innovation Through Plugins\"<br />
The post Unleashing Innovation Through Plugins appeared first on MariaDB.org.</p>
<p>The post <a rel="nofollow" href="https://mariadb.org/unleashing-innovation-through-plugins/">Unleashing Innovation Through Plugins</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>One of the corner stones in MariaDB Foundation&rsquo;s mission is:</p>
<p>We strive to increase adoption by users and across use cases, platforms and means of deployment. &hellip; </p>
<p class="link-more"><a href="https://mariadb.org/unleashing-innovation-through-plugins/" class="more-link">Continue reading<span class="screen-reader-text"> &ldquo;Unleashing Innovation Through Plugins&rdquo;</span></a></p>
<p>The post <a rel="nofollow" href="https://mariadb.org/unleashing-innovation-through-plugins/">Unleashing Innovation Through Plugins</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>

<p>The post <a rel="nofollow" href="https://mariadb.org/unleashing-innovation-through-plugins/">Unleashing Innovation Through Plugins</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Bringing pt-query-digest-Style Slow Query Analysis to PostgreSQL with pg_enhanced_query_logging</title>
      <link>https://www.percona.com/blog/bringing-pt-query-digest-style-slow-query-analysis-to-postgresql-with-pg_enhanced_query_logging/</link>
      <pubDate>Fri, 08 May 2026 01:52:10 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://www.percona.com/blog/">Blog - Percona</source>
      <description><![CDATA[<p>In this blog post, we are going to briefly discuss pg_enhanced_query_logging (PEQL for short), a PostgreSQL extension that produces slow query logs in the same format MySQL and Percona Server users have been feeding into pt-query-digest for years. The idea is simple: reuse the tried-and-true tools and concepts we have been using for performing full … Continued<br />
The post Bringing pt-query-digest-Style Slow Query Analysis to PostgreSQL with pg_enhanced_query_logging appeared first on Percona.</p>
<p>The post <a rel="nofollow" href="https://www.percona.com/blog/bringing-pt-query-digest-style-slow-query-analysis-to-postgresql-with-pg_enhanced_query_logging/">Bringing pt-query-digest-Style Slow Query Analysis to PostgreSQL with pg_enhanced_query_logging</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<div>In this blog post, we are going to briefly discuss <code><a href="https://github.com/guriandoro/pg_enhanced_query_logging">pg_enhanced_query_logging</a></code> (PEQL for short), a PostgreSQL extension that produces slow query logs in the same format MySQL and Percona Server users have been feeding into <code><a href="https://docs.percona.com/percona-toolkit/pt-query-digest.html">pt-query-digest</a></code> for years. The idea is simple: reuse the tried-and-true tools and concepts we have been using for performing full query audits with low performance hits. This tool was conceived and developed for the recent <a href="https://www.percona.com/blog/innovation-from-every-corner-inside-perconas-build-with-ai-competition/">Percona Build with AI Competition</a>.</div>
<div></div>
<div>A quick word of caution before we begin: PEQL is under active development and has not been validated for production use. We will use it in a development environment here, and you should do the same.</div>
<div></div>
<h2>Why a new slow log for PostgreSQL?<a class="anchor-link" id="why-a-new-slow-log-for-postgresql"></a></h2>
<div>Out of the box, PostgreSQL gives us <code>log_min_duration_statement</code> and a handful of related GUCs that print slow queries to the server log. That is useful, but the format is line-oriented and mixed in with everything else PostgreSQL writes there. On the MySQL side, the Percona Server <a href="https://docs.percona.com/percona-server/innovation-release/slow-extended.html">extended slow query log</a> goes much further: per-query counters, lock and I/O times, plan-quality flags, and a structured format that <code>pt-query-digest</code> can group by query fingerprint and rank by total time, average time, lock time, etc. This introduces the more powerful concept of performance of a family of queries, and not just individual query executions.</div>
<div>PEQL ports that same workflow to PostgreSQL. It hooks into the executor and planner, captures timing, buffer I/O, WAL, JIT and row-count metrics for every query slower than a configurable threshold, and writes them to a dedicated log file using a pt-query-digest-compatible format.</div>
<div></div>
<h2>Motivation and benefits<a class="anchor-link" id="motivation-and-benefits"></a></h2>
<div>The original idea behind this extension is doing query audits with minimal impact on the running server. We want to be able to ask &ldquo;what queries will we benefit more from tuning?&rdquo; without paying for it in latency, I/O or in a flood of unrelated log lines.</div>
<div>That goal drives most of the design decisions:</div>
<ul>
<li><strong>Statistically accurate sampling with low overhead.</strong> We don&rsquo;t need to log every single query to draw useful conclusions. PEQL can sample 1 out of every N queries (or 1 out of every N sessions), and doing this for enough time will mean that we can have a sample that represents the overall workload for that time period. The cost on the producer side stays low even on busy servers.</li>
<li><strong><em>pt-query-digest</em> compatibility out of the box.</strong> The output format mirrors the MySQL/Percona Server slow log, so the same toolchain we already use for MySQL audits works for PostgreSQL with no extra steps.</li>
<li><strong>Logging to a separate file.</strong> All entries go to a dedicated file (default <code>peql-slow.log</code>), not to PostgreSQL&rsquo;s main error log. That keeps the error log clean for actual errors and lets us point the slow log at a separate mountpoint if we want to isolate its I/O from the rest of the server.</li>
<li><strong>Rate limiting by both queries and bytes per second.</strong> On top of the per-session/per-query 1-in-N sampling, <code>peql.rate_limit_auto_max_queries</code> and <code>peql.rate_limit_auto_max_bytes</code> give us a cluster-wide cap on logged queries per second and on bytes written per second. Useful for guaranteeing that the slow log itself never becomes a performance issue.</li>
<li><strong>Always-log override for slow outliers.</strong> Even when sampling is on, <code>peql.rate_limit_always_log_duration</code> lets us say &ldquo;but always log anything that takes longer than X ms&rdquo;. The common queries get randomly sampled; the long-running ones always get logged.</li>
<li><strong>Extended resource usage metrics.</strong> Each entry includes buffer hit/read/dirtied/written counts (shared, local and temp), block I/O timings, WAL records/bytes/full-page images, JIT compilation timings, planning time, optional memory context allocations and an optional wait-event histogram.</li>
<li><strong>Execution plans embedded in the entry.</strong> With <code>peql.log_query_plan = on</code>, the full <code>EXPLAIN ANALYZE</code> output (text or JSON) is appended to each entry, so the plan that produced the metrics is right there next to them when we are reviewing the log later.</li>
<li><strong>Automatic pause when disk space is low.</strong> If the log mountpoint drops below a configurable free-space threshold, PEQL pauses logging on its own (with optional auto-purge of old rotated files) and resumes once there is room again. The database keeps serving traffic; the slow log gets out of the way.</li>
</ul>
<p>&nbsp;</p>
<h2>Installing the extension<a class="anchor-link" id="installing-the-extension"></a></h2>
<div>PEQL is a regular PGXS extension, to build it we can execute the following steps:</div>
<div>
<pre class="urvanov-syntax-highlighter-plain-tag">git clone https://github.com/guriandoro/pg_enhanced_query_logging.git
cd pg_enhanced_query_logging
make USE_PGXS=1
sudo make install USE_PGXS=1</pre>
</div>
<div>This installs the shared library into <code>$(pg_config --pkglibdir)</code> and the SQL/control files into <code>$(pg_config --sharedir)/extension/</code>. The hooks live in the shared library, so we need to preload it. Add the following line to <code>postgresql.conf</code> (or edit your current value to include it):</div>
<div>
<pre class="urvanov-syntax-highlighter-plain-tag">shared_preload_libraries = 'pg_enhanced_query_logging'</pre>
</div>
<div>Restart PostgreSQL, and then create the extension in any database where we want the SQL helper functions:</div>
<div>
<pre class="urvanov-syntax-highlighter-plain-tag">CREATE EXTENSION pg_enhanced_query_logging;</pre>
</div>
<div>To easily test it, the repository ships a Docker-based quick start that builds Rocky Linux 9 + PostgreSQL 18 with the extension preloaded:</div>
<div>
<pre class="urvanov-syntax-highlighter-plain-tag">./test/deploy_docker_pg18_rhel.sh</pre>
</div>
<p>&nbsp;</p>
<h2>A minimal configuration<a class="anchor-link" id="a-minimal-configuration"></a></h2>
<div>For a first look, the easiest thing to do is to log every query at full verbosity:</div>
<div>
<pre class="urvanov-syntax-highlighter-plain-tag">shared_preload_libraries = 'pg_enhanced_query_logging'
peql.log_min_duration = 0 # log every query
peql.log_verbosity = 'full' # emit all metric lines</pre>
</div>
<div>While we are at it, we can also silence PostgreSQL&rsquo;s native query logging so we have a single place to look:</div>
<div>
<pre class="urvanov-syntax-highlighter-plain-tag">log_statement = 'none'
log_min_duration_statement = -1
log_duration = off</pre>
</div>
<div>By default, PEQL writes to <code>peql-slow.log</code> inside PostgreSQL&rsquo;s <code>log_directory</code>. The location and filename are configurable via <code>peql.log_directory</code> and <code>peql.log_filename</code>.</div>
<div></div>
<h2>What an entry looks like<a class="anchor-link" id="what-an-entry-looks-like"></a></h2>
<div>After running a few queries, opening <code>peql-slow.log</code> shows entries like this one (trimmed for brevity):</div>
<div>
<pre class="urvanov-syntax-highlighter-plain-tag"># Time: 2026-03-11T09:15:32.847291
# User@Host: app_user[app_user] @ 10.0.1.42 []
# Thread_id: 48712 Schema: mydb.public
# Query_id: -6432758210044805760
# Query_time: 1.285034 Lock_time: 0.000000 Rows_sent: 256 Rows_examined: 87500
# Shared_blks_hit: 4096 Shared_blks_read: 312 Shared_blks_dirtied: 0 Shared_blks_written: 0
# Temp_blks_read: 0 Temp_blks_written: 48
# Shared_blk_read_time: 0.024310 Shared_blk_write_time: 0.000000
# WAL_records: 0 WAL_bytes: 0 WAL_fpi: 0
# Plan_time: 0.003210
# Full_scan: Yes Temp_table: No Temp_table_on_disk: Yes Filesort: Yes Filesort_on_disk: No
# JIT_functions: 4 JIT_generation_time: 0.001250 JIT_emission_time: 0.003100
SET timestamp=1741680931;
SELECT o.id, o.total, c.name FROM orders o JOIN customers c ON c.id = o.customer_id
WHERE o.status = 'pending' ORDER BY o.total DESC LIMIT 256;</pre>
<p>
The full breakdown of every field, with the GUCs that produce it, lives in <a href="https://github.com/guriandoro/pg_enhanced_query_logging/blob/master/doc/annotated-sample.md">doc/annotated-sample.md</a>. This is a great place to start reading the documentation.</p>
<p>&nbsp;</p>
</div>
<h2>Feeding it to pt-query-digest<a class="anchor-link" id="feeding-it-to-pt-query-digest"></a></h2>
<div>Because the format mirrors the MySQL slow log, we can point <code>pt-query-digest</code> at it directly:</div>
<div>
<pre class="urvanov-syntax-highlighter-plain-tag">pt-query-digest --type slowlog $(pg_config --logdir)/peql-slow.log</pre>
</div>
<div>We get the familiar profile at the top (queries grouped by fingerprint, ranked by total time), followed by the per-query detail blocks. The plan-quality flags above can also be used as filters, for example to look only at queries that did a sequential scan:</div>
<div>
<pre class="urvanov-syntax-highlighter-plain-tag">pt-query-digest --type slowlog 
--filter '$event-&gt;{Full_scan} eq "Yes"' 
$(pg_config --logdir)/peql-slow.log</pre>
<p>
If you do not have <code>pt-query-digest</code> installed, the standalone script can be downloaded directly:</p>
</div>
<div>
<pre class="urvanov-syntax-highlighter-plain-tag">curl -LO https://percona.com/get/pt-query-digest
chmod +x pt-query-digest</pre>
</div>
<p><span style="font-weight: 400">Example <code>pt-query-digest</code></span><span style="font-weight: 400">&nbsp;outputs will look like the following images.</span></p>
<figure id="attachment_45325" aria-describedby="caption-attachment-45325" style="width: 1024px" class="wp-caption aligncenter"><img decoding="async" loading="lazy" class="wp-image-45325 size-large" src="https://www.percona.com/wp-content/uploads/2026/05/global-1024x868.png" alt="" width="1024" height="868"><figcaption id="caption-attachment-45325" class="wp-caption-text">Queries grouped by fingerprint, ranked by total time.</figcaption></figure>
<figure id="attachment_45326" aria-describedby="caption-attachment-45326" style="width: 980px" class="wp-caption aligncenter"><img decoding="async" loading="lazy" class="wp-image-45326 size-large" src="https://www.percona.com/wp-content/uploads/2026/05/query-980x1024.png" alt="" width="980" height="1024"><figcaption id="caption-attachment-45326" class="wp-caption-text">Per-query detail blocks.</figcaption></figure>
<p>&nbsp;</p>
<h2>A few useful knobs<a class="anchor-link" id="a-few-useful-knobs"></a></h2>
<div>Once we move beyond logging everything, there are a handful of GUCs worth knowing about:</div>
<ul>
<li><code>peql.rate_limit</code>: 1-in-N sampling, either per session or per query, with a <code>peql.rate_limit_always_log_duration</code> override so that very slow queries are always captured even when sampling is on.</li>
<li><code>peql.log_parameter_values</code>: include actual bind parameter values for prepared statements alongside the placeholder query text.</li>
<li><code>peql.log_query_plan</code>: embed the full <code>EXPLAIN ANALYZE</code> output (text or JSON) inside the log entry, so the plan that produced the metrics is right there next to them. This can be expensive in terms of I/O, so use sparingly and only if needed.</li>
</ul>
<div>The full list, with default values and contexts, is documented in <a href="https://github.com/guriandoro/pg_enhanced_query_logging/blob/master/doc/configuration.md">doc/configuration.md</a>.</div>
<div></div>
<h2>Future work<a class="anchor-link" id="future-work"></a></h2>
<div>The <code>pt-query-digest</code> compatibility is a feature, but it&rsquo;s also a constraint: the MySQL slow log format was <span style="font-weight: 400">designed to be human readable</span>, which means it&rsquo;s way too verbose. For instance, the plan-quality flags line only has 5 bits of actual information, but uses around 100 bytes to encode them:</div>
<div>
<pre class="urvanov-syntax-highlighter-plain-tag"># Full_scan: Yes Temp_table: No Temp_table_on_disk: No Filesort: Yes Filesort_on_disk: No</pre>
</div>
<div>We can do this better by simply logging <code>YNNYN</code> or <code>10010</code> (hence the 5 bits of information mentioned above), and have the position within the query log entry make it self-explanatory as to what this information is.</div>
<div></div>
<div>This is a 20x amplification factor! And other lines suffer of similar issues&hellip; Multiply that by every query on a busy server and the overhead adds up quickly, both in disk space and in the I/O the backend has to do to write the entries out.</div>
<div></div>
<div>There are two pieces of follow-up work we have in mind to address this:</div>
<ol>
<li><strong>A PEQL-native log format.</strong> A more compact, structured format (think key-value pairs with short keys, bitfields for the boolean flags, or a binary framing for the numeric metrics) that drops the bytes-per-query cost without losing any of the information we currently emit. The verbose pt-query-digest-compatible format could still be available for users that want it; the native format would be the recommended option for high-throughput workloads.</li>
<li><strong>Tooling for the new format.</strong> Once the native format exists, we will either contribute a parser to <code>pt-query-digest</code> so that it can ingest it natively (<code>--type peql</code> or similar), or ship a small companion tool that either post-processes them or produces the same kind of profile reports <code>pt-query-digest</code> does today. Either way, the goal is to keep the analysis workflow we are used to while removing the format-imposed overhead from the producer side.</li>
</ol>
<div>If any of this sounds interesting and you would like to help shape it, the repository&rsquo;s <a href="https://github.com/guriandoro/pg_enhanced_query_logging/blob/master/doc/contributing.md">doc/contributing.md</a> is the right place to start.</div>
<div></div>
<h2>Conclusion<a class="anchor-link" id="conclusion"></a></h2>
<div>PostgreSQL has had rich per-query metrics available for a while now, but stitching them together into the kind of &ldquo;show me the worst-performing family of queries from the last hour&rdquo; workflow MySQL users have enjoyed for years has taken more effort. PEQL closes that gap by emitting a single, pt-query-digest-compatible log file with timing, buffer, WAL, JIT and plan-quality data attached to every query.</div>
<div></div>
<div>If you want to dig deeper, the <a href="https://github.com/guriandoro/pg_enhanced_query_logging/tree/master/doc">doc/</a> directory in the repository has detailed pages on the output format, the architecture of the hooks, the rate limiter and the disk-space protection logic. And if you have not used <code>pt-query-digest</code>&nbsp;before, this is a great time to do it!</div>
<p>The post <a href="https://www.percona.com/blog/bringing-pt-query-digest-style-slow-query-analysis-to-postgresql-with-pg_enhanced_query_logging/">Bringing pt-query-digest-Style Slow Query Analysis to PostgreSQL with pg_enhanced_query_logging</a> appeared first on <a href="https://www.percona.com">Percona</a>.</p>

<p>The post <a rel="nofollow" href="https://www.percona.com/blog/bringing-pt-query-digest-style-slow-query-analysis-to-postgresql-with-pg_enhanced_query_logging/">Bringing pt-query-digest-Style Slow Query Analysis to PostgreSQL with pg_enhanced_query_logging</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Meet the Percona Community team</title>
      <link>https://percona.community/blog/2026/05/07/meet-the-percona-community-team/</link>
      <pubDate>Thu, 07 May 2026 09:00:00 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://percona.community/blog/">Percona Community Blog - learn about MySQL, MariaDB, PostgreSQL, and MongoDB</source>
      <description><![CDATA[<p>We’ve just landed on X and Mastodon, and before the first real post goes out, we wanted to do something we don’t do often enough: introduce ourselves.</p>
<p>The post <a rel="nofollow" href="https://percona.community/blog/2026/05/07/meet-the-percona-community-team/">Meet the Percona Community team</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>We&rsquo;ve just landed on X and Mastodon, and before the first real post goes out, we wanted to do something we don&rsquo;t do often enough: introduce ourselves.</p>
<p>If you&rsquo;ve been to Percona Live, a Percona.connect, a PGConf, KubeCon, FOSDEM, or pretty much any open source database event in the past few years, you&rsquo;ve probably already met one of us. We&rsquo;re the people behind the booth, on stage, organising the speakers, herding the giant Jenga set, or trying to convince you to play a quick game of chess between sessions. Now we&rsquo;re also the people behind @PerconaCommunity on X and our new Mastodon account on the fediverse.</p>
<p>Each of us will sign our posts with our initials, so you&rsquo;ll always know who you&rsquo;re talking to. Here&rsquo;s who we are.</p>
<h2 id="laura-czajkowski---director-of-community-lc">Laura Czajkowski &ndash; Director of Community (LC)<a class="anchor-link" id="laura-czajkowski-director-of-community-lc"></a></h2>
<p>Laura runs the team. She&rsquo;s been in open source community work since the early 2000s, starting at the University of Limerick&rsquo;s Skynet computer society and going on to lead community at Canonical (Ubuntu), MongoDB, Couchbase, Vonage, Solace, and Dragonfly before joining Percona. Former Ubuntu LoCo Council and Community Council member. Outside work she&rsquo;s a Munster and Ireland rugby fan, runs a book club, plays tennis, and books regular trips to Disney World. Find her at <a href="https://laura.community" target="_blank" rel="noopener noreferrer">laura.community</a>.</p>
<h2 id="alastair-turner---postgres-community-advocate-at">Alastair Turner &ndash; Postgres Community Advocate (AT)<a class="anchor-link" id="alastair-turner-postgres-community-advocate-at"></a></h2>
<p>Alastair has been working with databases since 1995, settling on Postgres around 2002. If you&rsquo;ve spoken to anyone at Percona about PostgreSQL, Kubernetes, Transparent Data Encryption, or extensions, there&rsquo;s a good chance it was him. He writes regularly on the <a href="https://percona.community/" target="_blank" rel="noopener noreferrer">Percona Community blog</a> and speaks at PGConf events across Europe and North America. He&rsquo;s particularly interested in how open source communities work together &ndash; and what they can learn from each other.</p>
<h2 id="daniil-bazhenov---senior-community-manager-db">Daniil Bazhenov &ndash; Senior Community Manager (DB)<a class="anchor-link" id="daniil-bazhenov-senior-community-manager-db"></a></h2>
<p>Daniil organises our conference speakers, runs the Percona Forums, and has been a long-time contributor to the Percona Community blog. If you&rsquo;ve ever submitted a talk to Percona Live or asked a question on forums.percona.com, you&rsquo;ve crossed paths with him. He writes hands-on technical content too &ndash; GitOps with ArgoCD, PMM monitoring, Percona Everest from source &ndash; and hosts the Russian-language Percona Podcast.</p>
<h2 id="kyle-flanagan---global-manager-events-kf">Kyle Flanagan &ndash; Global Manager, Events (KF)<a class="anchor-link" id="kyle-flanagan-global-manager-events-kf"></a></h2>
<p>Kyle is the reason any of our events actually happen. He runs Percona&rsquo;s global events programme, from Percona Live and Percona.connect to our presence at Open Source Summit, KubeCon, and dozens of regional events each year. Before Percona, he ran executive events at Utah Valley University. If you&rsquo;ve grabbed a sticker at one of our booths, Kyle probably packed the box it came in.</p>
<h2 id="edith-puclla---technology-evangelist-ep">Edith Puclla &ndash; Technology Evangelist (EP)<a class="anchor-link" id="edith-puclla-technology-evangelist-ep"></a></h2>
<p>Originally from Peru, now based in London, Edith is a CNCF Ambassador, Docker Captain, and Data on Kubernetes Ambassador. Her background is in DevOps and infrastructure &ndash; Kubernetes, GPUs, Linux, distributed systems &ndash; and she contributes to translating Kubernetes documentation into Spanish through SIG-Operators. She&rsquo;s a regular speaker at FOSDEM, KubeCon, Cloud Native Rejekts, and Percona University events across Latin America.</p>
<h2 id="why-were-doing-this">Why we&rsquo;re doing this<a class="anchor-link" id="why-were-doing-this"></a></h2>
<p>We spend a lot of our time at events because that&rsquo;s where the most useful conversations happen &ndash; the ones over coffee, at the booth, in the hallway between talks. Being on social gives us a way to keep those conversations going when we&rsquo;re not in the same room. Expect event updates, contributor shout-outs, things we&rsquo;ve found useful, and the occasional opinion. If we&rsquo;ve shared it, we&rsquo;ve actually read it.</p>
<p>Photo below was taken at our recent team offsite in Antalya &ndash; five people who genuinely like working together, in case the smiles don&rsquo;t give it away.</p>
<p><figure>
<img decoding="async" src="https://percona.community/blog/2026/05/community-team-with-names.jpeg" alt="The Percona Community team in Antalya"></figure>
</p>
<p><strong>Find us:</strong></p>
<ul>
<li>X: <a href="https://x.com/PerconaBytes" target="_blank" rel="noopener noreferrer">@PerconaBytes</a></li>
<li>Mastodon: <a href="https://mastodon.social/@PerconaBytes" target="_blank" rel="noopener noreferrer">@PerconaBytes</a></li>
<li>Forums: <a href="https://forums.percona.com" target="_blank" rel="noopener noreferrer">forums.percona.com</a></li>
<li>Community blog: <a href="https://percona.community" target="_blank" rel="noopener noreferrer">percona.community</a></li>
</ul>
<p>Come say hi. If we&rsquo;re at an event near you, the booth is open &ndash; and so is the giant Jenga.</p>

<p>The post <a rel="nofollow" href="https://percona.community/blog/2026/05/07/meet-the-percona-community-team/">Meet the Percona Community team</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Adding a New Data Type to MariaDB with Type_handler – Part 5</title>
      <link>https://mariadb.org/adding-a-new-data-type-to-mariadb-with-type_handler-part-5/</link>
      <pubDate>Wed, 06 May 2026 13:51:44 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.org/">MariaDB.org</source>
      <description><![CDATA[<p>We are concluding our series related to new data types using the Type_handler framework, with some limitations that are not yet covered by the framework:<br />
It would have been handy for our MONEY datatype to have the possibility to define, for example, the currency to show. …<br />
Continue reading \"Adding a New Data Type to MariaDB with Type_handler – Part 5\"<br />
The post Adding a New Data Type to MariaDB with Type_handler – Part 5 appeared first on MariaDB.org.</p>
<p>The post <a rel="nofollow" href="https://mariadb.org/adding-a-new-data-type-to-mariadb-with-type_handler-part-5/">Adding a New Data Type to MariaDB with Type_handler – Part 5</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>We are concluding our series related to new data types using the Type_handler framework, with some limitations that are not yet covered by the framework:<br>
It would have been handy for our MONEY datatype to have the possibility to define, for example, the currency to show. &hellip; </p>
<p class="link-more"><a href="https://mariadb.org/adding-a-new-data-type-to-mariadb-with-type_handler-part-5/" class="more-link">Continue reading<span class="screen-reader-text"> &ldquo;Adding a New Data Type to MariaDB with Type_handler &ndash; Part 5&rdquo;</span></a></p>
<p>The post <a rel="nofollow" href="https://mariadb.org/adding-a-new-data-type-to-mariadb-with-type_handler-part-5/">Adding a New Data Type to MariaDB with Type_handler &ndash; Part 5</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>

<p>The post <a rel="nofollow" href="https://mariadb.org/adding-a-new-data-type-to-mariadb-with-type_handler-part-5/">Adding a New Data Type to MariaDB with Type_handler – Part 5</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>PSMDB Sandbox: A Browser-Based UI for Deploying MongoDB with Terraform and Ansible</title>
      <link>https://www.percona.com/blog/psmdb-sandbox-a-browser-based-ui-for-deploying-mongodb-with-terraform-and-ansible/</link>
      <pubDate>Tue, 05 May 2026 17:12:09 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://www.percona.com/blog/">Blog - Percona</source>
      <description><![CDATA[<p>If you’ve ever wrestled with .tfvars files, juggled Ansible inventory paths, or tried to remember the exact command sequence for a MongoDB setup — this post is for you. PSMDB Sandbox is a lightweight web frontend built in Go that ships inside the Percona MongoDB Automation repository. It puts a clean browser interface on top … Continued<br />
The post PSMDB Sandbox: A Browser-Based UI for Deploying MongoDB with Terraform and Ansible appeared first on Percona.</p>
<p>The post <a rel="nofollow" href="https://www.percona.com/blog/psmdb-sandbox-a-browser-based-ui-for-deploying-mongodb-with-terraform-and-ansible/">PSMDB Sandbox: A Browser-Based UI for Deploying MongoDB with Terraform and Ansible</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p><span style="font-weight: 400">If you&rsquo;ve ever wrestled with </span><span style="font-weight: 400">.tfvars</span><span style="font-weight: 400"> files, juggled Ansible inventory paths, or tried to remember the exact command sequence for a MongoDB setup &mdash; this post is for you.</span></p>
<p><a href="https://github.com/percona/mongo_terraform_ansible/tree/main/ui-go"><span style="font-weight: 400">PSMDB Sandbox</span></a><span style="font-weight: 400"> is a lightweight web frontend built in Go that ships inside the </span><a href="https://github.com/percona/mongo_terraform_ansible"><span style="font-weight: 400">Percona MongoDB Automation</span></a><span style="font-weight: 400"> repository. It puts a clean browser interface on top of the full Terraform + Ansible automation stack, so you can spin up, manage, and tear down MongoDB environments without ever touching a config file by hand.</span></p>
<p><span style="font-weight: 400">This project was built using vibe coding &mdash; the result is a fully functional application developed rapidly without writing every line from scratch. It&rsquo;s a great example of how AI-assisted development can accelerate tooling projects that would otherwise sit in the backlog forever.</span></p>
<h2><span style="font-weight: 400">Why a Web UI?</span><a class="anchor-link" id="why-a-web-ui"></a></h2>
<p><span style="font-weight: 400">The </span><a href="https://www.percona.com/blog/deploying-mongodb-test-environments-with-terraform-and-ansible/"><span style="font-weight: 400">mongo_terraform_ansible</span><span style="font-weight: 400"> project already automates a lot</span></a><span style="font-weight: 400">: it can deploy Percona Server for MongoDB (PSMDB), Percona Backup for MongoDB (PBM), and Percona Monitoring and Management (PMM</span><b>)</b><span style="font-weight: 400"> across AWS, GCP, Azure, Docker, and Libvirt/KVM. That&rsquo;s powerful &mdash; but the workflow traditionally meant editing </span><span style="font-weight: 400">.tfvars</span><span style="font-weight: 400"> files, running commands in the right order, and tracking state in your head.</span></p>
<p><span style="font-weight: 400">The Go UI changes that. It wraps the same Terraform and Ansible automation in a wizard-style interface, streams live output to your browser, and keeps track of environment state so you always know what&rsquo;s running, stopped, or in progress.</span></p>
<p><span style="font-weight: 400">It&rsquo;s particularly useful as a testing sandbox for PSMDB features. You can quickly spin up a replica set or sharded cluster, test backup and restore workflows with PBM, explore audit logging, and observe everything through PMM monitoring &mdash; all from the browser, and all torn down just as easily when you&rsquo;re done.</span></p>
<h2><span style="font-weight: 400">What You Can Configure</span><a class="anchor-link" id="what-you-can-configure"></a></h2>
<h3><span style="font-weight: 400">Cluster Topology</span><a class="anchor-link" id="cluster-topology"></a></h3>
<p><span style="font-weight: 400">Define how many clusters and replica sets you want, the number of nodes per replica set, and whether to deploy a sharded cluster or a simple replica set. Each cluster is independently configurable.</span></p>
<h3><span style="font-weight: 400">PSMDB Version and Packages</span><a class="anchor-link" id="psmdb-version-and-packages"></a></h3>
<p><span style="font-weight: 400">Pick the exact Percona Server for MongoDB release you want to test &mdash; package identifiers are fetched automatically from the Percona repository listing on startup, so you&rsquo;re always selecting from what&rsquo;s genuinely available. For Docker-based environments, image tags are pulled live from Docker Hub and cached for five minutes.</span></p>
<h3><span style="font-weight: 400">Backup and Restore with PBM</span><a class="anchor-link" id="backup-and-restore-with-pbm"></a></h3>
<p><span style="font-weight: 400">Percona Backup for MongoDB (PBM) can be included in the deployment. PBM is configured with the native storage backend for the supported environments (e.g. an S3 bucket is automatically created for AWS). This makes the sandbox ideal for testing backup policies, point-in-time recovery, and restore scenarios without touching production.</span></p>
<h3><span style="font-weight: 400">PMM Monitoring</span><a class="anchor-link" id="pmm-monitoring"></a></h3>
<p><span style="font-weight: 400">You can include a PMM Server in your environment so every PSMDB node is monitored from the moment it comes up. This makes it straightforward to test alerting rules, explore query analytics, or simply validate that your monitoring setup looks right before applying it elsewhere.</span></p>
<h2><span style="font-weight: 400">Live Deployment Logs</span><a class="anchor-link" id="live-deployment-logs"></a></h2>
<p><span style="font-weight: 400">When you hit </span><b>Deploy</b><span style="font-weight: 400">, the UI kicks off </span><span style="font-weight: 400">terraform init &amp;&amp; terraform apply</span><span style="font-weight: 400"> (plus Ansible playbooks for cloud platforms) in a background goroutine and streams the output directly to your browser via Server-Sent Events. No more tailing log files in a separate terminal.</span></p>
<h2><span style="font-weight: 400">Hosts &amp; Connections Panel</span><a class="anchor-link" id="hosts-connections-panel"></a></h2>
<p><span style="font-weight: 400">After a successful deployment, the environment detail page shows every host (or container) with:</span></p>
<ul>
<li style="font-weight: 400"><span style="font-weight: 400">Its IP address</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">A ready-to-copy connect command (</span><span style="font-weight: 400">ssh user@host</span><span style="font-weight: 400"> or </span><span style="font-weight: 400">docker exec -it &lt;name&gt; bash</span><span style="font-weight: 400">)</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">MongoDB connection strings for every replica set and cluster</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Clickable </span><b>Open</b><span style="font-weight: 400"> buttons for PMM and MinIO Console URLs</span></li>
</ul>
<h2><span style="font-weight: 400">Stop, Restart, Reset, and Destroy</span><a class="anchor-link" id="stop-restart-reset-and-destroy"></a></h2>
<p><span style="font-weight: 400">Full lifecycle management is available from the UI. For Docker environments, Stop and Restart call </span><span style="font-weight: 400">docker stop</span><span style="font-weight: 400"> / </span><span style="font-weight: 400">docker restart</span><span style="font-weight: 400"> filtered by the environment&rsquo;s prefix. For cloud environments, the corresponding Ansible </span><span style="font-weight: 400">stop.yml</span><span style="font-weight: 400"> and </span><span style="font-weight: 400">restart.yml </span><span style="font-weight: 400">playbooks run. Destroy calls </span><span style="font-weight: 400">terraform destroy</span><span style="font-weight: 400"> and, on success, automatically cleans up the inventory and redirects you back to the environments list.</span></p>
<h2><b>Getting Started</b><a class="anchor-link" id="getting-started"></a></h2>

<pre class="urvanov-syntax-highlighter-plain-tag">git clone https://github.com/percona/mongo_terraform_ansible.git
cd mongo_terraform_ansible/ui-go
go run .</pre>
<p><span style="font-weight: 400">Then open </span><a href="http://127.0.0.1:5001/"><span style="font-weight: 400">http://127.0.0.1:5001</span></a><span style="font-weight: 400"> in your browser.</span></p>
<p><span style="font-weight: 400">If you prefer a compiled binary:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">go build -o mongodeploy .
./mongodeploy</pre>
<p><span style="font-weight: 400">You can customize the bind address and port with environment variables:</span></p>
<p><b>Security note:</b><span style="font-weight: 400"> The UI is designed for local use. It binds to </span><span style="font-weight: 400">127.0.0.1</span><span style="font-weight: 400"> by default. Don&rsquo;t expose it to the public internet without adding authentication.</span></p>
<h2><b>Try It and Share Your Feedback</b><a class="anchor-link" id="try-it-and-share-your-feedback"></a></h2>
<p><span style="font-weight: 400">PSMDB Sandbox is a community-contributed tool. If you try it out, run into issues, or have ideas for improvements, open an issue or pull request on GitHub. The project is licensed under Apache 2.0.</span></p>
<p><span style="font-weight: 400">Happy deploying!</span></p>
<p>&nbsp;</p>
<p>The post <a href="https://www.percona.com/blog/psmdb-sandbox-a-browser-based-ui-for-deploying-mongodb-with-terraform-and-ansible/">PSMDB Sandbox: A Browser-Based UI for Deploying MongoDB with Terraform and Ansible</a> appeared first on <a href="https://www.percona.com">Percona</a>.</p>

<p>The post <a rel="nofollow" href="https://www.percona.com/blog/psmdb-sandbox-a-browser-based-ui-for-deploying-mongodb-with-terraform-and-ansible/">PSMDB Sandbox: A Browser-Based UI for Deploying MongoDB with Terraform and Ansible</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Adding a New Data Type to MariaDB with Type_handler – Part 4</title>
      <link>https://mariadb.org/adding-a-new-data-type-to-mariadb-with-type_handler-part-4/</link>
      <pubDate>Tue, 05 May 2026 09:30:53 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.org/">MariaDB.org</source>
      <description><![CDATA[<p>This is part 4 of a series related to extending MariaDB with a custom data type using the Type_handler framework.<br />
You can find the previous articles below:<br />
Overriding Existing Types<br />
In the previous examples, our MONEY data type inherits from DOUBLE and then we override some methods. …<br />
Continue reading \"Adding a New Data Type to MariaDB with Type_handler – Part 4\"<br />
The post Adding a New Data Type to MariaDB with Type_handler – Part 4 appeared first on MariaDB.org.</p>
<p>The post <a rel="nofollow" href="https://mariadb.org/adding-a-new-data-type-to-mariadb-with-type_handler-part-4/">Adding a New Data Type to MariaDB with Type_handler – Part 4</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>This is part 4 of a series related to extending MariaDB with a custom data type using the Type_handler framework.<br>
You can find the previous articles below:<br>
Overriding Existing Types<a id="overriding-existing-types"></a><br>
In the previous examples, our MONEY data type inherits from DOUBLE and then we override some methods. &hellip; </p>
<p class="link-more"><a href="https://mariadb.org/adding-a-new-data-type-to-mariadb-with-type_handler-part-4/" class="more-link">Continue reading<span class="screen-reader-text"> &ldquo;Adding a New Data Type to MariaDB with Type_handler &ndash; Part 4&rdquo;</span></a></p>
<p>The post <a rel="nofollow" href="https://mariadb.org/adding-a-new-data-type-to-mariadb-with-type_handler-part-4/">Adding a New Data Type to MariaDB with Type_handler &ndash; Part 4</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>

<p>The post <a rel="nofollow" href="https://mariadb.org/adding-a-new-data-type-to-mariadb-with-type_handler-part-4/">Adding a New Data Type to MariaDB with Type_handler – Part 4</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>How I Stopped Babysitting My Coding Agent (With Dotfiles)</title>
      <link>https://percona.community/blog/2026/05/05/how-i-stopped-babysitting-my-coding-agent-with-dotfiles/</link>
      <pubDate>Tue, 05 May 2026 00:00:00 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://percona.community/blog/">Percona Community Blog - learn about MySQL, MariaDB, PostgreSQL, and MongoDB</source>
      <description><![CDATA[<p>Most developers at least try to use coding agents for development-related tasks, but babysitting LLMs and managing their permissions is no fun. Completely skipping permission checks is a dangerous idea on your main machine, and setting up containers or VMs for sandboxing is a pain. Can we do better?</p>
<p>The post <a rel="nofollow" href="https://percona.community/blog/2026/05/05/how-i-stopped-babysitting-my-coding-agent-with-dotfiles/">How I Stopped Babysitting My Coding Agent (With Dotfiles)</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>Most developers at least try to use coding agents for development-related tasks, but babysitting LLMs and managing their permissions is no fun.<br>
Completely skipping permission checks is a dangerous idea on your main machine, and setting up containers or VMs for sandboxing is a pain.<br>
Can we do better?</p>
<h3 id="the-autonomy-problem">The autonomy problem<a class="anchor-link" id="the-autonomy-problem"></a></h3>
<p>If you work in software development, you have most certainly heard the phrase:</p>
<blockquote>
<p>Let&rsquo;s just use an LLM to solve it!</p>
</blockquote>
<p>People tend to forget that it&rsquo;s a bit more complicated than this:<br>
anybody can easily use LLMs, of course, but using them properly is a different question.<br>
Ideally, we could all just download a simple tool, give it some instructions, and relax:</p>
<p><figure><img decoding="async" src="https://percona.community/blog/2026/05/ai-gardening.png" alt="&nbsp;"></figure>
</p>
<div class="admonition admonition--warning">
<p>Disclaimer: your employer might not approve if you do gardening during work hours; I suggest choosing a different activity in this case!</p>
</div>
<p>In all seriousness, every panel in the above image contains details that people tend to ignore, which either results in inefficient workflows or the creation of slop.</p>
<p>We can&rsquo;t talk about all of them in one go; it would be overly long and complex.<br>
I&rsquo;ll only focus on panel 2:<br>
what can we do to ensure our uninterrupted <del>gardening</del> normal work?</p>
<p>If you simply download Claude/Codex and start using the CLI tool, VS Code extension, or anything else, you&rsquo;ll quickly get bored of all the babysitting.</p>
<blockquote>
<p>Hey, user, can I execute another slightly different <code>ls</code> command?</p>
</blockquote>
<p>Either you decide it isn&rsquo;t worth the effort because of all the interruptions, or you start blindly hitting Enter: &ldquo;of course I approve, it should be safe&hellip;&rdquo;</p>
<ol>
<li>Are you really thoroughly reviewing every command it throws at you?</li>
<li>Even that 100-line bash script the TUI doesn&rsquo;t display properly, because it wouldn&rsquo;t fit on the screen?</li>
<li>Have you ever seen an agent circumvent directory permissions by accessing the restricted files through a one-off script instead?</li>
</ol>
<p>Fine-grained permissions of course exist, and in theory, you could try to configure something like that.<br>
But let&rsquo;s be honest, most of us won&rsquo;t take the time, and we likely won&rsquo;t notice if (3) happens as part of a long script.</p>
<h3 id="let-the-ai-run-free">Let the AI run free<a class="anchor-link" id="let-the-ai-run-free"></a></h3>
<p>That&rsquo;s the point where you might discover the other option:<br>
completely disabling the permission system and letting the AI do whatever it wants.</p>
<p>Nothing can go wrong, it&rsquo;s only on your machine, right?</p>
<p><figure><img decoding="async" src="https://percona.community/blog/2026/05/ai-running.png" alt="&nbsp;"></figure>
</p>
<p>Except that:</p>
<ul>
<li>it will also have full network access, both for reading and posting</li>
<li>it can read all your secrets: its own OAuth token, your SSH key, and so on&hellip;</li>
<li>do you load your SSH key into ssh-agent? That&rsquo;s convenient so you don&rsquo;t have to enter your password every time, but do you also have a hardware key you have to touch on every use, or can the AI force-push your repository and later say</li>
</ul>
<blockquote>
<p>You are absolutely right! I shouldn&rsquo;t have done that. If you have backups you can restore them with the following steps: &hellip;</p>
</blockquote>
<p>Or it might end up in any number of similar situations.<br>
Coding agents aren&rsquo;t malicious by design, but they can be subject to prompt injection from the web, or simply reach dumb conclusions.<br>
There&rsquo;s a good reason why Claude, for example, calls this option <code>--dangerously-skip-permissions</code>.</p>
<h3 id="put-them-in-a-cage">Put them in a cage!<a class="anchor-link" id="put-them-in-a-cage"></a></h3>
<p>The next obvious choice is to let them run free, but only within a cell:<br>
run the agent inside a container or virtual machine, where it can only access what you let it.</p>
<p>This, however, costs us some convenience, as we face new issues:</p>
<ul>
<li>If we completely separate the environment, we can&rsquo;t access it from our main system.<br>
Allowing AI tools to push to your repo without confirmation is a bad idea, but maybe you yourself should be able to push somehow?<br>
Or to verify the changes in a more complex, outside environment?</li>
<li>Our environment and the AI&rsquo;s environment are different&hellip; which means we have to set up both.<br>
I hope your project is easy to bootstrap, with proper scripting so you don&rsquo;t have to do this by hand.<br>
But is your development environment also easy to bootstrap?</li>
</ul>
<p>There are some existing, ready-to-use solutions: for example, both Claude Code and OpenAI Codex have support for <a href="https://containers.dev/" target="_blank" rel="noopener noreferrer">devcontainers</a>.<br>
If you want an easy setup, these can be an option.</p>
<p>However, I wanted more:<br>
to replicate my main setup exactly &ndash; the same compilers, tools, shell and editor settings, and so on.<br>
The AI tools should have the same executables available.<br>
If I have to edit or do something directly in the container, I shouldn&rsquo;t be surprised by something working differently.</p>
<p>That&rsquo;s when I remembered: I already have a <a href="https://github.com/dutow/dotfiles" target="_blank" rel="noopener noreferrer">dotfiles</a> repo. Can I make it even better for this use case?</p>
<h3 id="automate-all-the-things">Automate all the things!<a class="anchor-link" id="automate-all-the-things"></a></h3>
<p>The idea of dotfiles is simple:<br>
a repository where you store your configuration, so when you reinstall your system, or when you have to start using another one, you can quickly replicate your preferred settings.<br>
Editors, shells, git &ndash; everything works the same, without spending hours figuring it all out again.</p>
<p>The problem is that it usually only focuses on configuring an already properly installed system.<br>
When you only buy a new PC every few years, or system administrators already set up every server you have to use before your first login, this isn&rsquo;t a big issue.</p>
<p>But when you want to be able to quickly set up and iterate with throwaway systems?<br>
Then you need better automation!</p>
<p>This is also a solved problem; tools like Ansible and Puppet exist.</p>
<p>The idea is simple:</p>
<ul>
<li>instead of manually setting up your system, use an automation tool to install and configure everything</li>
<li>you can leverage free CI services to make sure that your scripts work when run on a clean system</li>
<li>while docker/podman traditionally uses its own setup scripting, it is possible to build an image using the same automation tool instead</li>
<li>the result? Main PC, containers, virtual machines, and quick VPS instances all behaving exactly the same way!</li>
</ul>
<p>The downside is, of course, that you either have to reinstall your main PC once your new setup is good enough, or accept that it will be slightly different until you do so.<br>
I went with the reinstall; it&rsquo;s easy once you have things working.</p>
<p>And if you don&rsquo;t know any of these tools?<br>
That&rsquo;s the best part &ndash; we&rsquo;re using AI, and AI knows them well.</p>
<h3 id="a-side-note-on-architecture">A side note on architecture<a class="anchor-link" id="a-side-note-on-architecture"></a></h3>
<p>The focus of this blog post is panel 2, not the others.<br>
But I want to at least mention that the architecture and human review, including design review, are as important as with any other AI-driven software project.</p>
<p>If you completely vibe-code it and create an unmaintainable, sloppy dotfiles configuration, you are going to regret it later. This is your everyday work environment.</p>
<p>After the initial idea, when I started to think more about my requirements, I quickly realized that I want something generic.</p>
<p>First, I want to install a different set of packages depending on where I am installing them: containers, WSL instances, or real machines.<br>
My laptop needs slightly different settings compared to my desktop.</p>
<p>Second, I want to be able to do this on multiple distributions.<br>
Previously it was really annoying when I had to debug a distro-specific bug, unless it happened to involve one of my primary Linux distributions.<br>
I am also using a different OS on my work laptop and personal desktop PC because of company requirements.</p>
<p>With a proper Ansible setup, I can make all of these work seamlessly, even autodetecting the environment, and verifying all important configurations on CI for every commit.</p>
<p>Your requirements will most likely be different.<br>
Think about these beforehand and structure your repository accordingly!</p>
<h3 id="containers-or-virtual-machines">Containers or virtual machines?<a class="anchor-link" id="containers-or-virtual-machines"></a></h3>
<p>So far I mentioned both as alternatives, and both have their pros and cons.</p>
<table>
<thead>
<tr>
<th>Aspect</th>
<th>Container</th>
<th>Virtual machine</th>
</tr>
</thead>
<tbody>
<tr>
<td>Resource overhead</td>
<td>Low</td>
<td>Higher</td>
</tr>
<tr>
<td>Spin-up time</td>
<td>Seconds</td>
<td>Minutes</td>
</tr>
<tr>
<td>Host integration (mounts, networks)</td>
<td>Easy, direct</td>
<td>Network only</td>
</tr>
<tr>
<td>Isolation from host</td>
<td>Partial</td>
<td>Strong</td>
</tr>
<tr>
<td>GUI / IDE support</td>
<td>Limited, terminal-friendly</td>
<td>Full desktop</td>
</tr>
<tr>
<td>Privileged tools (GDB, GPU)</td>
<td>Extra capabilities required</td>
<td>Native, inside the VM</td>
</tr>
<tr>
<td>Credential storage</td>
<td>Shares host&rsquo;s filesystem</td>
<td>Must duplicate (SSH key, hardware key)</td>
</tr>
</tbody>
</table>
<p>For now, I went with containers.<br>
With a few helper scripts I can mount specific directories from the host OS, and I can also specify which docker/podman network the new container should join.<br>
This lets me start up my docker-compose development clusters directly on my main OS, and lets the agent access the development/test database and other containers for its work using the shared network.</p>
<div class="code-block">
<div class="code-block__header"><button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-0">
<div class="highlight">
<pre class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">dcont run --mount `pwd` --network hackorum_default --context main-dev</span></span></code></pre>
</div>
</div>
</div>
<p>I even have a <code>context</code> parameter, which lets me keep multiple independent AI configurations: different system-level CLAUDE.md, plugin set, hooks, and so on.<br>
Underneath, this is just a few specific mounts and symlinks, but the advantage is huge:</p>
<ul>
<li>I can quickly experiment without fearing that I&rsquo;ll break my main workflows</li>
<li>I have completely separate setups for development and review work, without them conflicting with each other</li>
</ul>
<p>The upsides are easy integration, lower resource overhead, and quicker spin-up.<br>
I can mount directories directly from the host, and easily interact with docker containers running on the host.</p>
<p>The downside comes from that same integration:<br>
everything is still on the host, and the more access you give to the container, the less secure it becomes.<br>
Tools like GDB and GPU access require extra privileges, and you might have to relax SELinux features for the container.</p>
<p>The privilege problem, and the possibility of giving the container too much access, is a real risk.<br>
Docker, which runs as root on the host, and rootless podman, which maps the container root to the current host user, behave very differently if something is misconfigured &ndash; but neither protects the data accessible to the running user.</p>
<p>You can tighten the defaults with flags like <code>--cap-drop=ALL</code>, <code>--security-opt=no-new-privileges</code>, and read-only mounts where possible, but these only narrow the attack surface; they don&rsquo;t fix what you mount in.<br>
Which means what you mount matters more than which runtime you pick.</p>
<h4 id="mounts-and-credentials">Mounts and credentials</h4>
<p><code>.env</code> files, for example, can be challenging:<br>
these can contain API keys, passwords, and other secrets required by the application, which ideally shouldn&rsquo;t be accessible to the coding agent.<br>
I started using two levels of them &ndash; one in the project folder with only generic data, and another one level above containing sensitive login information for external services.<br>
This way, when I mount the project folder, the container can&rsquo;t access the sensitive <code>.env</code> file.</p>
<p>There are also some special files to watch out for:<br>
mounting <code>/var/run/docker.sock</code> into the container, for example, can break the sandbox completely, as it grants access equivalent to root on the host.</p>
<h4 id="when-to-pick-a-vm-instead">When to pick a VM instead</h4>
<p>A container also isn&rsquo;t a full-fledged desktop.<br>
Personally, I am used to working in terminals; I like tools like tmux or neovim.<br>
But if you prefer desktop applications and IDEs, a full virtual machine might be a better option.</p>
<p>Full virtual machines aren&rsquo;t more difficult to set up and give you a complete GUI, but they raise a different question:<br>
how do you set everything up without accidental credential leaks?</p>
<p>You either rely on network synchronization between your main OS and the virtual machine &ndash; pushing to remotes only from the main OS &ndash; or you give the virtual machine a hardware key and store your SSH key on it.</p>
<p>Agents can of course always access and leak their own API keys; we can&rsquo;t do anything about that with 100% certainty.<br>
But we can aim to reduce their ability to leak anything else, by minimizing what they physically have access to.</p>
<h3 id="an-example-setup">An example setup<a class="anchor-link" id="an-example-setup"></a></h3>
<p>You can check out my <a href="https://github.com/dutow/dotfiles" target="_blank" rel="noopener noreferrer">dotfiles</a> for inspiration.<br>
It should be only that:<br>
something you can look at while designing your own version.</p>
<p>It is designed for my workflows, and yours are most likely different.<br>
You also shouldn&rsquo;t blindly trust a script somebody else&rsquo;s LLM generated.</p>
<h4 id="the-helper-script">The helper script</h4>
<p>The repository has a readme; the most interesting part is probably <a href="https://github.com/dutow/dotfiles/blob/master/dcont" target="_blank" rel="noopener noreferrer">the script I mentioned earlier</a>, which builds and runs the containers.</p>
<p>It is long and complex, and deals with additional details I didn&rsquo;t even mention here, to keep this introduction from getting too involved.</p>
<p>The basic idea, however, is easy to summarize.<br>
A basic docker command is simple:</p>
<div class="code-block">
<div class="code-block__header"><button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-1">
<div class="highlight">
<pre class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">docker run -it ubuntu:latest /bin/bash</span></span></code></pre>
</div>
</div>
</div>
<p>But it also gets complicated quickly:</p>
<ul>
<li>what folders need mounting? (the project, specific directories for tools)</li>
<li>which networks to join?</li>
<li>do we have to set up specific hardware, like a GPU?</li>
<li>do we need specific access permissions for some software?</li>
<li>and so on</li>
</ul>
<p>The command quickly becomes longer and longer, and copy-pasting it from notes or shell history isn&rsquo;t fun.<br>
It is also most likely project-specific.<br>
You want different mounts, different contexts for AIs, different specific permissions.<br>
All this should be configurable, and still simple.</p>
<p>In my case, most of my projects also have <code>.env</code> files set up, which makes it a no-brainer to also support configuration through environment variables.</p>
<p>Most of the time, all I have to do is <code>cd</code> into the project directory and execute <code>dcont</code> without any extra parameters. That starts up a ready-to-use, project-specific setup, and I can immediately start typing instructions to Claude.</p>
<h4 id="the-ansible-part">The Ansible part</h4>
<p>I already mentioned this before, but didn&rsquo;t go into the details:<br>
you can build docker or podman images with Ansible.</p>
<p>Normally this isn&rsquo;t that useful:<br>
if the only goal is a container cluster, a Containerfile is much easier to use, and more efficient for rebuilding, since it automatically detects which layers have to be rebuilt.</p>
<p>If the goal, however, is to replicate the same setup on a real host and in a container, the picture is different.<br>
These images are only meant for local use, so layering and image size don&rsquo;t matter &ndash; we&rsquo;ll never upload them.</p>
<p>Build times are also secondary.<br>
Even if a rebuild is needed once or twice a day, you can continue using the previous version in the meantime and switch later.<br>
And it&rsquo;s not like we can&rsquo;t do proper incremental builds with it; Ansible supports that too &ndash; it&rsquo;s just a bit slower than how containers normally do it.</p>
<p>This is included in the same script, and the solution is surprisingly simple:</p>
<ol>
<li>start a container with <code>sleep infinity</code></li>
<li>copy the dotfiles repo into it, since it&rsquo;s already checked out on the host</li>
<li>run the same dotfiles/Ansible script as on other hosts (with proper parameters)</li>
<li>set up a proper user</li>
<li>commit the image</li>
</ol>
<p>The same could be done using a <code>Containerfile</code>, but what&rsquo;s the advantage?<br>
The image isn&rsquo;t shareable or reusable anyway, and some operations are easier to implement directly in bash.<br>
This process also leaves open the possibility of doing incremental builds, instead of always rerunning the installation script from scratch.</p>
<h3 id="the-unsaid-part-network-access">The unsaid part: network access<a class="anchor-link" id="the-unsaid-part-network-access"></a></h3>
<p>In all of the sandboxing discussion above, I quietly ignored the question of network access:<br>
if you give unrestricted network access to an LLM agent, you can have a bad time.</p>
<p>Prompt injection exists, even if AI companies try to make it harder and harder.</p>
<p>For most use cases, a complete network ban is also a bad idea for productivity and code quality, which makes this another complex, open-ended question with its own options and tradeoffs &ndash; out of scope for this already long blog post.</p>
<p>I hope the information I provided here was useful, and that you can improve your AI setup based on it!</p>

<p>The post <a rel="nofollow" href="https://percona.community/blog/2026/05/05/how-i-stopped-babysitting-my-coding-agent-with-dotfiles/">How I Stopped Babysitting My Coding Agent (With Dotfiles)</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Long live to dbdeployer!</title>
      <link>https://mariadb.org/long-live-to-dbdeployer/</link>
      <pubDate>Mon, 04 May 2026 14:22:15 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.org/">MariaDB.org</source>
      <description><![CDATA[<p>As you know, MySQL-Sandbox and then dbdeployer have always been part of the Swiss Army knife for DBAs trying to evaluate, test, or reproduce issues with a certain version of their database. …<br />
Continue reading \"Long live to dbdeployer!\"<br />
The post Long live to dbdeployer! appeared first on MariaDB.org.</p>
<p>The post <a rel="nofollow" href="https://mariadb.org/long-live-to-dbdeployer/">Long live to dbdeployer!</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>As you know, MySQL-Sandbox and then dbdeployer have always been part of the Swiss Army knife for DBAs trying to evaluate, test, or reproduce issues with a certain version of their database. &hellip; </p>
<p class="link-more"><a href="https://mariadb.org/long-live-to-dbdeployer/" class="more-link">Continue reading<span class="screen-reader-text"> &ldquo;Long live to dbdeployer!&rdquo;</span></a></p>
<p>The post <a rel="nofollow" href="https://mariadb.org/long-live-to-dbdeployer/">Long live to dbdeployer!</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>

<p>The post <a rel="nofollow" href="https://mariadb.org/long-live-to-dbdeployer/">Long live to dbdeployer!</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>I Know Kung Fu</title>
      <link>https://www.percona.com/blog/i-know-kung-fu/</link>
      <pubDate>Mon, 04 May 2026 12:43:46 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://www.percona.com/blog/">Blog - Percona</source>
      <description><![CDATA[<p>You might find this hard to believe, but AI has become kind of a thing around here. Bennie published a post on our Build with AI competition last week, in which he shared that I was lucky enough to land the second place prize. Genuinely flattered, and a real thank you to Peter F, PZ, … Continued<br />
The post I Know Kung Fu appeared first on Percona.</p>
<p>The post <a rel="nofollow" href="https://www.percona.com/blog/i-know-kung-fu/">I Know Kung Fu</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>You might find this hard to believe, but AI has become kind of a thing around here.</p>
<p>Bennie published a post on our <a href="https://www.percona.com/blog/innovation-from-every-corner-inside-perconas-build-with-ai-competition/">Build with AI competition</a> last week, in which he shared that I was lucky enough to land the second place prize. Genuinely flattered, and a real thank you to Peter F, PZ, Vadim, and Bennie for organizing it. The recognition is great. But the part that does not quite come through in the recap is what those six weeks actually felt like from the inside. Forty-plus submissions, 10+ teams, marathon demo sessions that ran out of time twice over, and a constant drumbeat of ideas where every fifth one made me think &ldquo;wait, we can just&hellip; ship that?&rdquo;</p>
<p>Two submissions that really impressed me (and are worthy of high praise): Kedar Vaijanapurkar shipped <a href="https://nitty-witty.com/">a four-tool MySQL stack</a> (Advisor, random data generator, CleanPrompt, and a Query Reviewer), any one of which on its own would have been a strong submission. And Daniil built a leaderboard for Percona ecosystem contributors plus a vector-search prototype running on Percona&rsquo;s own products, which is exactly the dogfood story we want.</p>
<p>There were a lot more than three projects worth backing, which is part of why a second contest round is being coordinated later this year. A lot of the entries are not waiting for it either &ndash; they are already developing into real, operational utilities (some of mine included).</p>
<p>The two submissions of my own that I would point to first are <strong>IBEX</strong> and <strong>percona-dk</strong>.</p>
<p><strong>IBEX</strong> (Integration Bridge for EXtended systems) is a local MCP multi-tool server that connects either a local model or a Percona-owned LLM to the systems where the most valuable context actually lives. Slack, Notion, Jira, ServiceNow, Salesforce, etc. A solution was needed here since we could not point the standard Claude or ChatGPT connectors at our sensitive internal data, and obviously most of the context that makes LLMs so valuable is precisely that kind of data.</p>
<p><a href="https://github.com/Percona-Lab/percona-dk"><strong>percona-dk</strong></a> is the other one. It started as a way to keep AI honest about our own products by giving the AI tools our teams use (Claude, Cursor, anything that speaks MCP) direct access to Percona&rsquo;s documentation, so the answer to a question about our products comes from real docs with linked citations instead of stale training data or even scraped web results that can get things wrong. It has evolved a fair bit since the contest. The Percona Community blog and forums are now indexed alongside the docs, Perconians are getting real day-to-day value out of it, and it is starting to look like the kind of thing that could grow into a community utility (perhaps even beyond Percona docs).</p>
<p>Those two were just the start. Once IBEX worked, I needed shared memory across LLMs, so I built that. Once I had three MCP servers running, the boilerplate got annoying, so I built <a href="https://github.com/Percona-Lab/CAIRN"><strong>CAIRN</strong></a>, a scaffolding tool that builds on Anthropic&rsquo;s official MCP builder skill. The official skill walks you through writing a server step by step, but CAIRN spins up a complete, working project in minutes with a streamlined install wizard for non-technical users. It is now in the hands of other Perconians building their own MCP tools, and providing real value of its own. Then I learned about .mcpb files and Desktop Extensions (.dxt), packaged everything that way, and stood up an internal Claude plugin marketplace so any Perconian can install the lot from one place. Each layer opened a door I did not know existed until I was already through it. Some of those doors seemingly materialized from thin air as they magically aligned with new releases from Anthropic.</p>
<p>What started as a competition entry is now a small internal ecosystem. I am still a product person, not a software engineer. I am not going to pretend any of the code is pristine, and a lot of it was vibe-coded with Claude as a partner. But the architecture holds together, it works, and most of it is in daily use by people who are not me. That last part is the bit I am most proud of.</p>
<p>The next batch is pointed squarely at product operations. Making customer signals legible. Making internal telemetry something any teammate can talk to in plain English. The early returns are promising, and what gets me most excited is not the tech itself, it is watching people across Product, Engineering, and Support pull in the same direction with an AI colleague in the room. Turns out the interesting part of AI at work is not the model. It is the connective tissue.</p>
<h4>I know Kung Fu</h4>
<p>For a product guy who does not code for a living, this era is my &ldquo;I know kung fu&rdquo; moment. Not because I suddenly learned to fight. Because the move set I already had &ndash; product judgment, systems thinking, customer empathy, the ability to spec a thing precisely &ndash; just got a massive upgrade. The gap between &ldquo;that would be useful&rdquo; and &ldquo;that exists now&rdquo; is short enough to cross in an evening. I do not see it getting longer again.</p>
<p>Thanks for reading this far. If you want more detail or want to try anything not linked here, ping me. I am happy to share more.</p>
<p><!-- notionvc: fc8a336b-f88d-4d72-931c-1b57605ac9ad --></p>
<p>The post <a href="https://www.percona.com/blog/i-know-kung-fu/">I Know Kung Fu</a> appeared first on <a href="https://www.percona.com">Percona</a>.</p>

<p>The post <a rel="nofollow" href="https://www.percona.com/blog/i-know-kung-fu/">I Know Kung Fu</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Adding a New Data Type to MariaDB with Type_handler – Part 3</title>
      <link>https://mariadb.org/adding-a-new-data-type-to-mariadb-with-type_handler-part-3/</link>
      <pubDate>Mon, 04 May 2026 06:27:16 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.org/">MariaDB.org</source>
      <description><![CDATA[<p>In the previous article, we wrote, compiled, and tested our first custom data type for MariaDB using the Type_handler framework.<br />
But currently, aside from allowing the use of its new name (MONEY) and listing it in the metadata, our new data type behaves exactly like a DOUBLE, the class it inherits from. …<br />
Continue reading \"Adding a New Data Type to MariaDB with Type_handler – Part 3\"<br />
The post Adding a New Data Type to MariaDB with Type_handler – Part 3 appeared first on MariaDB.org.</p>
<p>The post <a rel="nofollow" href="https://mariadb.org/adding-a-new-data-type-to-mariadb-with-type_handler-part-3/">Adding a New Data Type to MariaDB with Type_handler – Part 3</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>In <a href="https://mariadb.org/adding-a-new-data-type-to-mariadb-with-type_handler-part-2/">the previous article</a>, we wrote, compiled, and tested our first custom data type for MariaDB using the Type_handler framework.<br>
But currently, aside from allowing the use of its new name (MONEY) and listing it in the metadata, our new data type behaves exactly like a DOUBLE, the class it inherits from. &hellip; </p>
<p class="link-more"><a href="https://mariadb.org/adding-a-new-data-type-to-mariadb-with-type_handler-part-3/" class="more-link">Continue reading<span class="screen-reader-text"> &ldquo;Adding a New Data Type to MariaDB with Type_handler &ndash; Part 3&rdquo;</span></a></p>
<p>The post <a rel="nofollow" href="https://mariadb.org/adding-a-new-data-type-to-mariadb-with-type_handler-part-3/">Adding a New Data Type to MariaDB with Type_handler &ndash; Part 3</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>

<p>The post <a rel="nofollow" href="https://mariadb.org/adding-a-new-data-type-to-mariadb-with-type_handler-part-3/">Adding a New Data Type to MariaDB with Type_handler – Part 3</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Curious case of PXC node that refused to start due to SSL</title>
      <link>https://www.percona.com/blog/curious-case-of-pxc-node-that-refused-to-start-due-to-ssl/</link>
      <pubDate>Mon, 04 May 2026 05:45:15 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://www.percona.com/blog/">Blog - Percona</source>
      <description><![CDATA[<p>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 … Continued<br />
The post Curious case of PXC node that refused to start due to SSL appeared first on Percona.</p>
<p>The post <a rel="nofollow" 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 rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p><span style="font-weight: 400">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 style="font-weight: 400">Let&rsquo;s see how the maintenance goes. It was supposed to be a simple restart. </span><span style="font-weight: 400">The kind you&rsquo;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&hellip; because MySQL refused to start.</span></p>
<h2><span style="font-weight: 400">The Problem</span><a class="anchor-link" id="the-problem"></a></h2>
<p><span style="font-weight: 400">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>&nbsp;</p>
<p><span style="font-weight: 400">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 style="font-weight: 400">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 style="font-weight: 400">Clients connected over TLS. Galera nodes communicated securely. There were zero complaints from the error log.<br>
</span><span style="font-weight: 400">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 style="font-weight: 400">Checking Usual Suspects</span><a class="anchor-link" id="checking-usual-suspects"></a></h2>
<p><b>File permissions</b></p>
<p><span style="font-weight: 400">We checked the PEM files.&nbsp;</span></p>
<p><span style="font-weight: 400">Ownership: <code>mysql:mysql</code>.<br>
</span><span style="font-weight: 400">Permissions: <code>644</code> for the cert, <code>600</code> for the key.&nbsp;</span></p>
<p><span style="font-weight: 400">We compared them against the other Galera nodes, and they were identical. This didn&rsquo;t look like a permissions problem.</span></p>
<p><b>Is SELinux to blame here?</b></p>
<p><span style="font-weight: 400">SELinux has ruined enough DBA time that it is one of the top spots on such checklists &ndash; but it was permissive.</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">$ getenforce
<span style="font-weight: 400">Permissive</span></pre>
<p><span style="font-weight: 400">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 style="font-weight: 400">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 style="font-weight: 400">The files were fine. They parsed cleanly. OpenSSL could read them. So why couldn&rsquo;t MySQL?</span></p>
<p><b>More Logs review</b></p>
<p><span style="font-weight: 400">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 &ldquo;I am the Dhurandhar that&rsquo;s destroyed your node.&rdquo;&nbsp;</span><span style="font-weight: 400">At this point, most of the usual suspects were guilt-free, staring at us, asking, &ldquo;Who did it?&rdquo;</span></p>
<h2><span style="font-weight: 400">The Clue</span><a class="anchor-link" id="the-clue"></a></h2>
<p><span style="font-weight: 400">It is good to communicate with stakeholders, and we did &ndash; &ldquo;Was there any recent change on your side?&rdquo; to the client, and then uttered the golden words &ldquo;Last week the crypto-policy was updated on all of the DB servers to comply with PCI.&rdquo;</span></p>
<p><span style="font-weight: 400">PCI &gt; Crypto-policy &ndash; Let&rsquo;s go and check it !!</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">$ update-crypto-policies --show
FUTURE</pre>
<p><span style="font-weight: 400">The system was running RHEL&rsquo;s FUTURE cryptographic policy.</span></p>
<p><span style="font-weight: 400">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&rsquo;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&hellip; like MySQL.</span></p>
<p>Here&rsquo;s a table that shows information about the crypto-policy levels:</p>
<table class="alignleft" style="height: 237px;width: 622px;border-style: solid;border-color: #000000" border="1">
<tbody>
<tr style="height: 47px">
<td style="width: 62.1875px;height: 47px"><span style="font-weight: 400">Policy</span></td>
<td style="width: 92.3125px;height: 47px"><span style="font-weight: 400">RSA Minimum</span></td>
<td style="width: 91.3125px;height: 47px"><span style="font-weight: 400">TLS Minimum</span></td>
<td style="width: 101.344px;height: 47px"><span style="font-weight: 400">SHA-1 Signatures</span></td>
<td style="width: 240.844px;height: 47px"><span style="font-weight: 400">Use Case</span></td>
</tr>
<tr style="height: 42px">
<td style="width: 62.1875px;height: 42px"><span style="font-weight: 400">LEGACY</span></td>
<td style="width: 92.3125px;height: 42px"><span style="font-weight: 400">1024-bit</span></td>
<td style="width: 91.3125px;height: 42px"><span style="font-weight: 400">TLS 1.0</span></td>
<td style="width: 101.344px;height: 42px"><span style="font-weight: 400">Allowed</span></td>
<td style="width: 240.844px;height: 42px"><span style="font-weight: 400">Old systems compatibility</span></td>
</tr>
<tr style="height: 46px">
<td style="width: 62.1875px;height: 46px"><span style="font-weight: 400">DEFAULT</span></td>
<td style="width: 92.3125px;height: 46px"><span style="font-weight: 400">2048-bit</span></td>
<td style="width: 91.3125px;height: 46px"><span style="font-weight: 400">TLS 1.2</span></td>
<td style="width: 101.344px;height: 46px"><span style="font-weight: 400">Allowed</span></td>
<td style="width: 240.844px;height: 46px"><span style="font-weight: 400">Standard operations</span></td>
</tr>
<tr style="height: 44px">
<td style="width: 62.1875px;height: 44px"><span style="font-weight: 400">FUTURE</span></td>
<td style="width: 92.3125px;height: 44px"><span style="font-weight: 400">3072-bit</span></td>
<td style="width: 91.3125px;height: 44px"><span style="font-weight: 400">TLS 1.2</span></td>
<td style="width: 101.344px;height: 44px"><span style="font-weight: 400">Blocked</span></td>
<td style="width: 240.844px;height: 44px"><span style="font-weight: 400">Forward-looking hardening</span></td>
</tr>
<tr style="height: 58px">
<td style="width: 62.1875px;height: 58px"><span style="font-weight: 400">FIPS</span></td>
<td style="width: 92.3125px;height: 58px"><span style="font-weight: 400">2048-bit</span></td>
<td style="width: 91.3125px;height: 58px"><span style="font-weight: 400">TLS 1.2</span></td>
<td style="width: 101.344px;height: 58px"><span style="font-weight: 400">Blocked</span></td>
<td style="width: 240.844px;height: 58px"><span style="font-weight: 400">FIPS 140 compliance</span></td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span style="font-weight: 400">So FUTURE demands a 3072-bit RSA key; otherwise, it is blocked. What do we have?</span><span style="font-weight: 400"><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 style="font-weight: 400">2048 bits! C&rsquo;mon! And now I recall the error log again&hellip; 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 style="font-weight: 400">Now we have our story straight.<br>
</span><span style="font-weight: 400">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: &ldquo;Nope. Too small.&rdquo;</span></p>
<h2><span style="font-weight: 400">Fixture</span><a class="anchor-link" id="fixture"></a></h2>
<p><span style="font-weight: 400">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 style="font-weight: 400">This will accept the current SSLs, and the node will join the cluster readily.</span></p>
<p><span style="font-weight: 400">Alternatively, to remain compliant and adhere to the security policy strictness, the fixture will be to</span></p>
<ul>
<li style="font-weight: 400"><span style="font-weight: 400">Generate new certificates</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Deploy the keys/certs to all Galera nodes</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Perform a rolling restart</span></li>
</ul>
<p>&nbsp;</p>
<h2><span style="font-weight: 400">Conclusion</span><a class="anchor-link" id="conclusion"></a></h2>
<p><span style="font-weight: 400">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 style="font-weight: 400">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>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</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>

<p>The post <a rel="nofollow" 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 rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Building Query Analysis and Insights Dashboard in PMM</title>
      <link>https://www.percona.com/blog/building-query-analysis-and-insights-dashboard-in-pmm/</link>
      <pubDate>Mon, 04 May 2026 05:00:52 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://www.percona.com/blog/">Blog - Percona</source>
      <description><![CDATA[<p>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 … Continued<br />
The post Building Query Analysis and Insights Dashboard in PMM appeared first on Percona.</p>
<p>The post <a rel="nofollow" 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 rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p><span style="font-weight: 400">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 style="font-weight: 400">We all know and love the Query Analytics (QAN) dashboard&hellip; It&rsquo;s the first place we look when an incident alert fires or when a developer asks, </span><i><span style="font-weight: 400">&ldquo;Why is the app slow?&rdquo; or &ldquo;What was going on during the midnight production outage?&rdquo;</span></i></p>
<p><span style="font-weight: 400">But sometimes, the standard dashboards just don&rsquo;t tell the whole story or maybe are not clear enough. QAN is great, but shouldn&rsquo;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 style="font-weight: 400">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&rsquo;t just looking for &ldquo;slow&rdquo; queries anymore; we are hunting for inefficiency, volatility, and the &ldquo;silent killers&rdquo; that standard monitoring often misses.</span></p>
<p><span style="font-weight: 400">This is the hands-on blog, so grab your coffee and let&rsquo;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 style="font-weight: 400"><span style="font-weight: 400">Connect to PMM &gt; Dashboards &gt; Create New Dashboard<img decoding="async" loading="lazy" class="alignnone wp-image-43360" src="https://www.percona.com/wp-content/uploads/2026/04/pmm-new-dashboard.png" alt="" width="172" height="160"></span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Save it with name &ldquo;Slow Query Analysis&rdquo; and Description &ldquo;Slow Query Analysis from PMM&rsquo;s QAN database (clickhouse)&rdquo;</span><img decoding="async" loading="lazy" class="alignnone wp-image-43359" src="https://www.percona.com/wp-content/uploads/2026/04/pmm-save-dashboard.png" alt="" width="681" height="258"></li>
<li style="font-weight: 400"><span style="font-weight: 400">Click on add visualisation &amp; select datasource &ldquo;ClickHouse&rdquo;<br>
<img decoding="async" loading="lazy" 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"><br>
</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Choose SQL Builder<br>
<img decoding="async" loading="lazy" 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"><br>
</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Paste the following query to get top 10 slow queries from the database<br>
</span>
<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 style="font-weight: 400"><span style="font-weight: 400">Choose &ldquo;Table View&rdquo; on the top to view the list<br>
</span><span style="font-weight: 400">When you click &ldquo;Run Query&rdquo; you will see the top 10 slow queries in the chosen time period.<img decoding="async" loading="lazy" 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"></span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Let&rsquo;s Save the dashboard after Panel Options updates as follows</span><span style="font-weight: 400">7.1 Change Panel Name and Description to: &ldquo;Slow Query Analysis&rdquo;</span><span style="font-weight: 400">7.2 Legend Placement to &ldquo;Bottom&rdquo;, Values to &ldquo;min&rdquo;,&rdquo;max&rdquo;, &ldquo;mean&rdquo;</span><span style="font-weight: 400">7.3 Change Axis&rsquo; Scale to &ldquo;Logarithmic&rdquo;</span><i><span style="font-weight: 400">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 style="font-weight: 400">7.4 Save Dashboard<img decoding="async" loading="lazy" 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"></span><span style="font-weight: 400">Alright, we&rsquo;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 style="font-weight: 400"> 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&rsquo;s refine the dashboard to focus on specific queries, servers and observe their performance over time.</span><span style="font-weight: 400">Now, let&rsquo;s introduce a variable to filter the data.</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Click on </span><b>Settings</b><span style="font-weight: 400"> on Dashboard&rsquo;s home page</span><img decoding="async" loading="lazy" 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">8.1 Choose &ldquo;Variables&rdquo; tab and click on &ldquo;Add Variable&rdquo;<img decoding="async" loading="lazy" 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">8.2 Add variable configuration and Save Dashboard&nbsp;</li>
<li style="font-weight: 400"><span style="font-weight: 400">Go Back to Dashboard and Edit &ldquo;Slow Query Analysis&rdquo; Panel.</span>
<ul>
<li style="font-weight: 400"><span style="font-weight: 400">Now you should see the Query ID filter on the top.</span></li>
</ul>
</li>
<li style="font-weight: 400"><span style="font-weight: 400">Change the query to the following<br>
</span>
<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 style="font-weight: 400"><span style="font-weight: 400">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 style="font-weight: 400"><span style="font-weight: 400">There is a filter for the &ldquo;queryid&rdquo; variable which you may use if you want to filter on a specific queryid.</span></li>
<li style="font-weight: 400">Choose &ldquo;Time Series&rdquo; as &ldquo;Query Type&rdquo;<img decoding="async" loading="lazy" 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"></li>
</ul>
</li>
<li style="font-weight: 400"><span style="font-weight: 400">Adjust Panel Options</span><span style="font-weight: 400">11.1 Choose &ldquo;Standard options&rdquo; &gt; &ldquo;Unit&rdquo; as &ldquo;Time / Seconds (s)&rdquo; from drop down.</span><span style="font-weight: 400">11.2 Choose &ldquo;Standard options&rdquo; &gt; &ldquo;Display name&rdquo; as &ldquo;</span><span style="font-weight: 400">${__field.labels.query_text}</span><span style="font-weight: 400">&rdquo;</span><span style="font-weight: 400">11.3 Click on &ldquo;Save Dashboard&rdquo;</span></li>
<li><span style="font-weight: 400"> Your dashboard should be ready<img decoding="async" loading="lazy" 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"></span></li>
</ol>
<p><span style="font-weight: 400">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.&nbsp; That said, this is still plotting queries across all the monitored instances. Let&rsquo;s move on to add the service_name filter.</span></p>
<p>&nbsp;</p>
<h3><b>Adding service_name filter</b><a class="anchor-link" id="adding-service_name-filter"></a></h3>
<ol>
<li style="font-weight: 400"><span style="font-weight: 400">Add Variable</span>
<ol>
<li style="font-weight: 400"><span style="font-weight: 400">Create new variable named &ldquo;service_name&rdquo;</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Use variable type &ldquo;Query&rdquo;</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Use Data Source as &ldquo;ClickHouse&rdquo;</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Query:<br>
</span>
<pre class="urvanov-syntax-highlighter-plain-tag">select distinct service_name from pmm.metrics where service_type = 'mysql';</pre>
</li>
<li><span style="font-weight: 400">Unselect all checkboxes in &ldquo;Selection options&rdquo;</span></li>
<li><span style="font-weight: 400">Save Dashboard</span></li>
</ol>
</li>
<li>Update Query</li>
</ol>
<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 style="font-weight: 400">I know many of you are naturally curious and enjoy experimenting with PMM and Grafana&hellip; So you&rsquo;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 style="font-weight: 400">Sample Dashboards:</span></p>
<p><img decoding="async" loading="lazy" 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"> <img decoding="async" loading="lazy" 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"></p>
<h1><span style="font-weight: 400">The Query Analysis and Insights Dashboard</span><a class="anchor-link" id="the-query-analysis-and-insights-dashboard"></a></h1>
<p><span style="font-weight: 400">Okay, for those who are looking to have quick results, I&rsquo;ve prepared the complete Query Analysis and Insights Dashboard for you to import and use instantly.</span></p>
<p><span style="font-weight: 400">By importing the JSON file, you&rsquo;ll get the full working dashboard with all panels preconfigured, including:</span></p>
<ul>
<li><span style="font-weight: 400">Slow Query Analysis</span></li>
<li><span style="font-weight: 400">Latency Distribution Heatmap</span></li>
<li><span style="font-weight: 400">Query Volatility (P99 vs Average)</span></li>
<li><span style="font-weight: 400">Lock Wait Ratio Over Time (Top Contended Queries)</span></li>
<li><span style="font-weight: 400">Temporary Table Usage (Disk &amp; Memory)</span></li>
<li><span style="font-weight: 400">Query Efficiency (Rows Examined vs Rows Sent)</span></li>
<li><span style="font-weight: 400">Error Rate vs Throughput</span></li>
<li><span style="font-weight: 400">Workload Distribution by User</span></li>
<li><span style="font-weight: 400">Query Volume by Client Host</span></li>
<li><span style="font-weight: 400">Execution Time vs Lock Wait Time</span></li>
</ul>
<p><span style="font-weight: 400">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 style="font-weight: 400">Dashboard JSON available here:</span></p>
<ul>
<li style="font-weight: 400"><span style="font-weight: 400">Grafana: https://grafana.com/grafana/dashboards/24896</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">GitHub:&nbsp; https://github.com/Percona-Lab/pmm-dashboards/query_analysis_insights.json</span></li>
</ul>
<p><span style="font-weight: 400">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>

<p>The post <a rel="nofollow" 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 rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Adding a New Data Type to MariaDB with Type_handler – Part 2</title>
      <link>https://mariadb.org/adding-a-new-data-type-to-mariadb-with-type_handler-part-2/</link>
      <pubDate>Sat, 02 May 2026 18:12:27 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.org/">MariaDB.org</source>
      <description><![CDATA[<p>After having discovered the Type_hander framework and learned how to build MariaDB Server from source, it’s time to code our first data type! …<br />
Continue reading \"Adding a New Data Type to MariaDB with Type_handler – Part 2\"<br />
The post Adding a New Data Type to MariaDB with Type_handler – Part 2 appeared first on MariaDB.org.</p>
<p>The post <a rel="nofollow" href="https://mariadb.org/adding-a-new-data-type-to-mariadb-with-type_handler-part-2/">Adding a New Data Type to MariaDB with Type_handler – Part 2</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>After having <a href="https://mariadb.org/adding-a-new-data-type-to-mariadb-with-type_handler-part-1/" target="_blank" rel="noreferrer noopener">discovered the Type_hander framework</a> and learned <a href="https://mariadb.org/adding-a-new-data-type-to-mariadb-with-type_handler-part-0/">how to build MariaDB Server from source</a>, it&rsquo;s time to code our first data type! &hellip; </p>
<p class="link-more"><a href="https://mariadb.org/adding-a-new-data-type-to-mariadb-with-type_handler-part-2/" class="more-link">Continue reading<span class="screen-reader-text"> &ldquo;Adding a New Data Type to MariaDB with Type_handler &ndash; Part 2&rdquo;</span></a></p>
<p>The post <a rel="nofollow" href="https://mariadb.org/adding-a-new-data-type-to-mariadb-with-type_handler-part-2/">Adding a New Data Type to MariaDB with Type_handler &ndash; Part 2</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>

<p>The post <a rel="nofollow" href="https://mariadb.org/adding-a-new-data-type-to-mariadb-with-type_handler-part-2/">Adding a New Data Type to MariaDB with Type_handler – Part 2</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>InnoDB Redo Log Sizing: Stop Guessing, Start Measuring</title>
      <link>https://percona.community/blog/2026/05/02/innodb-redo-log-sizing-stop-guessing-start-measuring/</link>
      <pubDate>Sat, 02 May 2026 00:00:00 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://percona.community/blog/">Percona Community Blog - learn about MySQL, MariaDB, PostgreSQL, and MongoDB</source>
      <description><![CDATA[<p>Introduction Many MySQL configurations inherit redo log sizing from defaults, aging blog posts, or configuration folklore.</p>
<p>The post <a rel="nofollow" href="https://percona.community/blog/2026/05/02/innodb-redo-log-sizing-stop-guessing-start-measuring/">InnoDB Redo Log Sizing: Stop Guessing, Start Measuring</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<h2 id="introduction">Introduction<a class="anchor-link" id="introduction"></a></h2>
<p>Many MySQL configurations inherit redo log sizing from defaults, aging blog posts, or configuration folklore.</p>
<p><code>innodb_redo_log_capacity</code> gets set once&hellip; and then quietly fades into the background.</p>
<p>But redo log capacity directly shapes how efficiently MySQL absorbs writes, manages checkpoint pressure, and handles burst-heavy workloads.</p>
<p>Set it too low, and aggressive flushing can throttle throughput.<br>
Set it too high, and crash recovery can become painfully long.</p>
<p>Redo logs are more than crash insurance.</p>
<p>They are part of your write-performance architecture.</p>
<blockquote>
<p>Redo logs are the shock absorbers of write-heavy MySQL. Too small, and performance jolts. Too large, and recovery drags.</p>
</blockquote>
<h2 id="why-redo-logs-matter">Why Redo Logs Matter<a class="anchor-link" id="why-redo-logs-matter"></a></h2>
<p>InnoDB redo logs are often described as crash recovery journals, but that description undersells their real operational value.</p>
<p>Redo logs function as a write buffer between committed transactions and eventual data file writes.</p>
<p>When a transaction commits:</p>
<ul>
<li>Changes are written to the redo log first</li>
<li>Dirty pages remain in memory</li>
<li>Data pages are flushed later</li>
</ul>
<p>This write-ahead logging (WAL) design allows MySQL to:</p>
<ul>
<li>Absorb bursts of write activity</li>
<li>Reduce immediate random disk writes</li>
<li>Smooth checkpoint behavior</li>
<li>Preserve durability</li>
</ul>
<p>Redo logs act like pressure regulators in a write-heavy system.</p>
<p>They absorb pressure spikes so the entire system doesn&rsquo;t thrash every time demand increases.</p>
<p>Without enough redo capacity, MySQL has less room to absorb write bursts before it must flush aggressively.</p>
<h2 id="checkpoint-age-and-flushing-pressure">Checkpoint Age and Flushing Pressure<a class="anchor-link" id="checkpoint-age-and-flushing-pressure"></a></h2>
<p>Redo log sizing becomes most visible when checkpoint pressure builds.</p>
<p>Checkpoint age represents how far current write activity has advanced beyond the last durable checkpoint:</p>
<p><code>Checkpoint Age = Current LSN - Last Checkpoint LSN</code></p>
<p>As checkpoint age approaches total redo capacity:</p>
<ul>
<li>Adaptive flushing intensifies</li>
<li>Page cleaners become more aggressive</li>
<li>Dirty pages flush faster</li>
<li>Disk I/O spikes</li>
<li>Latency often becomes unstable</li>
</ul>
<p>This is where undersized redo logs can trigger flush storms.</p>
<blockquote>
<p>MySQL isn&rsquo;t writing more data. It&rsquo;s being forced to write sooner and less efficiently.</p>
</blockquote>
<h3 id="useful-metrics">Useful metrics<a class="anchor-link" id="useful-metrics"></a></h3>
<ul>
<li><code>Innodb_checkpoint_age</code></li>
<li><code>Innodb_buffer_pool_pages_dirty</code></li>
<li><code>Innodb_data_fsyncs</code></li>
<li><code>Innodb_log_waits</code></li>
</ul>
<blockquote>
<p>When redo space shrinks, MySQL doesn&rsquo;t stop writing. It starts panicking earlier.</p>
</blockquote>
<h2 id="symptoms-of-undersized-redo">Symptoms of Undersized Redo<a class="anchor-link" id="symptoms-of-undersized-redo"></a></h2>
<p>Small redo logs rarely announce themselves directly.</p>
<p>Instead, they often masquerade as generalized storage or write-performance issues.</p>
<h3 id="common-warning-signs">Common warning signs<a class="anchor-link" id="common-warning-signs"></a></h3>
<ul>
<li>Periodic write stalls</li>
<li>Spikes in fsync activity</li>
<li>Sharp increases in page cleaner workload</li>
<li>TPS drops during burst traffic</li>
<li>Dirty page percentage volatility</li>
<li>Stable CPU, unstable write latency</li>
</ul>
<h3 id="a-common-misdiagnosis">A common misdiagnosis<a class="anchor-link" id="a-common-misdiagnosis"></a></h3>
<p>Many systems blame disks when the real issue is insufficient redo headroom.</p>
<p>If writes are arriving faster than redo can comfortably buffer them, MySQL is forced into reactive flushing patterns.</p>
<p>The problem may not be disk speed.</p>
<p>It may be timing pressure.</p>
<h2 id="measuring-with-status-counters">Measuring with Status Counters<a class="anchor-link" id="measuring-with-status-counters"></a></h2>
<p>Redo log sizing should be based on observed workload, not memory percentages or inherited defaults.</p>
<h3 id="step-1-measure-redo-generation-rate">Step 1: Measure redo generation rate<a class="anchor-link" id="step-1-measure-redo-generation-rate"></a></h3>
<p>Use:</p>
<div class="code-block">
<div class="code-block__header"><span class="code-block__lang">sql</span><button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-0">
<div class="highlight">
<pre class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SHOW</span><span class="w"> </span><span class="n">ENGINE</span><span class="w"> </span><span class="n">INNODB</span><span class="w"> </span><span class="n">STATUS</span><span class="p">;</span></span></span></code></pre>
</div>
</div>
</div>
<p>Track:</p>
<ul>
<li>Log sequence number</li>
<li>Log flushed up to</li>
<li>Last checkpoint at</li>
</ul>
<p>Measure LSN growth over time:</p>
<p><code>Redo Generation Rate = (LSN delta) / elapsed time</code></p>
<h3 id="example">Example<a class="anchor-link" id="example"></a></h3>
<p>If LSN grows by 4 GB over one hour:</p>
<ul>
<li>1 GB redo capacity = frequent pressure</li>
<li>4 GB redo capacity = ~1 hour buffer</li>
<li>8 GB redo capacity = larger burst tolerance</li>
</ul>
<h3 id="step-2-watch-for-log-stress">Step 2: Watch for log stress<a class="anchor-link" id="step-2-watch-for-log-stress"></a></h3>
<div class="code-block">
<div class="code-block__header"><span class="code-block__lang">sql</span><button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-1">
<div class="highlight">
<pre class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SHOW</span><span class="w"> </span><span class="k">GLOBAL</span><span class="w"> </span><span class="n">STATUS</span><span class="w"> </span><span class="k">LIKE</span><span class="w"> </span><span class="s1">'Innodb_log_waits'</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">SHOW</span><span class="w"> </span><span class="k">GLOBAL</span><span class="w"> </span><span class="n">STATUS</span><span class="w"> </span><span class="k">LIKE</span><span class="w"> </span><span class="s1">'Innodb_os_log%'</span><span class="p">;</span></span></span></code></pre>
</div>
</div>
</div>
<h3 id="key-metric">Key metric<a class="anchor-link" id="key-metric"></a></h3>
<p><code>Innodb_log_waits</code></p>
<p>If this value increases, transactions are waiting for log free space.</p>
<p>That is one of the clearest signs your redo logs may be too small.</p>
<p><code>Innodb_log_waits</code> is less a tuning suggestion and more a smoke alarm.</p>
<h2 id="practical-sizing-strategy">Practical Sizing Strategy<a class="anchor-link" id="practical-sizing-strategy"></a></h2>
<p>Forget percentage-of-RAM formulas.</p>
<p>Redo logs should be sized around workload intensity.</p>
<p><strong>A practical starting point:</strong></p>
<p>Size redo capacity to hold 30 to 60 minutes of peak redo generation</p>
<h3 id="example-1">Example<a class="anchor-link" id="example"></a></h3>
<p>Peak redo generation = 6 GB/hour</p>
<p><strong>Minimum:</strong></p>
<p>30 minutes = 3 GB</p>
<p><strong>Safer:</strong></p>
<p>60 minutes = 6 GB</p>
<p><strong>Heavy burst environments:</strong></p>
<p>Larger sizing may reduce flush volatility further</p>
<h2 id="trade-offs">Trade-Offs<a class="anchor-link" id="trade-offs"></a></h2>
<h3 id="smaller-redo-logs">Smaller Redo Logs<a class="anchor-link" id="smaller-redo-logs"></a></h3>
<p><strong>Pros:</strong></p>
<ul>
<li>Faster crash recovery</li>
<li>Lower storage footprint</li>
</ul>
<p><strong>Cons:</strong></p>
<ul>
<li>Increased checkpoint pressure</li>
<li>More aggressive flushing</li>
<li>Greater write instability</li>
</ul>
<h3 id="larger-redo-logs">Larger Redo Logs<a class="anchor-link" id="larger-redo-logs"></a></h3>
<p><strong>Pros:</strong></p>
<ul>
<li>Better burst absorption</li>
<li>Smoother sustained write performance</li>
<li>Reduced flush storms</li>
</ul>
<p><strong>Cons:</strong></p>
<ul>
<li>Longer crash recovery</li>
<li>Delayed visibility into pressure buildup</li>
</ul>
<h2 id="common-mistakes">Common Mistakes<a class="anchor-link" id="common-mistakes"></a></h2>
<ol>
<li>
<p><strong>Treating redo like buffer pool sizing</strong><br>
Redo capacity is about write throughput buffering, not memory caching.</p>
</li>
<li>
<p><strong>Ignoring Innodb_log_waits</strong><br>
This can leave obvious pressure invisible until performance suffers.</p>
</li>
<li>
<p><strong>Oversizing without testing recovery</strong><br>
Large redo logs may improve runtime but worsen restart scenarios.</p>
</li>
<li>
<p><strong>Sizing for average load instead of peak</strong><br>
Redo logs exist to absorb pressure spikes, not calm periods.</p>
</li>
</ol>
<h2 id="final-thoughts">Final Thoughts<a class="anchor-link" id="final-thoughts"></a></h2>
<p>The right redo log size isn&rsquo;t about maximizing a configuration value.</p>
<p>It&rsquo;s about matching capacity to workload behavior.</p>
<ul>
<li>Too small, and MySQL becomes reactive.</li>
<li>Too large, and crash recovery becomes the hidden tax.</li>
</ul>
<p>When redo logs are properly sized, they fade into the background.</p>
<p>They quietly absorb bursts, smooth checkpoint behavior, and preserve performance consistency under pressure.</p>
<blockquote>
<p>Redo logs work best when they disappear into the background, quietly absorbing pressure instead of creating it.</p>
</blockquote>
<p>Stop guessing.</p>
<p>Measure your workload, observe your log pressure, and size with intent.</p>

<p>The post <a rel="nofollow" href="https://percona.community/blog/2026/05/02/innodb-redo-log-sizing-stop-guessing-start-measuring/">InnoDB Redo Log Sizing: Stop Guessing, Start Measuring</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Run an ALTER TABLE for a huge table in Aurora</title>
      <link>https://www.percona.com/blog/run-an-alter-table-for-a-huge-table-in-aurora/</link>
      <pubDate>Fri, 01 May 2026 01:55:40 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://www.percona.com/blog/">Blog - Percona</source>
      <description><![CDATA[<p>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 … Continued<br />
The post Run an ALTER TABLE for a huge table in Aurora appeared first on Percona.</p>
<p>The post <a rel="nofollow" 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 rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p><span style="font-weight: 400">Recently, we received an alert for one of our </span><a href="https://www.percona.com/services/managed-services"><span style="font-weight: 400">Managed Services</span></a><span style="font-weight: 400"> 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 style="font-weight: 400">At 80%, we have enough time to change it to BIGINT.&hellip;. Right? Let&rsquo;s see.</span></p>
<p><span style="font-weight: 400">So we used </span><a href="https://docs.percona.com/percona-toolkit/pt-online-schema-change.html"><span style="font-weight: 400">pt-online-schema-change</span></a><span style="font-weight: 400"> to perform the alter.</span></p>
<p><span style="font-weight: 400">It started running at a good pace but slowed over time.</span></p>
<p>&nbsp;</p>
<p><b>Why?</b></p>
<p><span style="font-weight: 400">Well, let&rsquo;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 ***************************
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Table: mytable
Create Table: CREATE TABLE `mytable` (
&nbsp;&nbsp;`id` int unsigned NOT NULL AUTO_INCREMENT,
&nbsp;&nbsp;`long_column` varchar(1000) NOT NULL,
&nbsp;&nbsp;`state` tinyint unsigned NOT NULL,
&nbsp;&nbsp;`created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
&nbsp;&nbsp;`short_column` varchar(30) NOT NULL,
&nbsp;&nbsp;PRIMARY KEY (`id`),
&nbsp;&nbsp;KEY `idx_long_column` (`long_column`,`state`),
&nbsp;&nbsp;KEY `idx_short_column` (`short_column`,`state`),
&nbsp;&nbsp;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 style="font-weight: 400">The index on </span><i><span style="font-weight: 400">long_column</span></i><span style="font-weight: 400"> 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 style="font-weight: 400"> The index </span><i><span style="font-weight: 400">idx_short_col2</span></i><span style="font-weight: 400"> is duplicated, as it is covered by the index </span><i><span style="font-weight: 400">idx_short_column</span></i><span style="font-weight: 400">.</span></p>
<p><span style="font-weight: 400">Those changes require testing and are out of scope for this emergency, but they are worth mentioning.</span></p>
<p>&nbsp;</p>
<p><strong>Table size:</strong><span style="font-weight: 400"><br>
</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">+---------------+------------+------------+---------+----------+---------+----------+--------+
| TABLE_SCHEMA&nbsp; | TABLE_NAME | TABLE_ROWS | DATA_GB | INDEX_GB | FREE_GB | TOTAL_GB | ENGINE |
+---------------+------------+------------+---------+----------+---------+----------+--------+
| myschema      | mytable    | 3906921584 |&nbsp; &nbsp; 1118 | &nbsp; &nbsp; 1790 | &nbsp; &nbsp; &nbsp; 0 | &nbsp; &nbsp; 2907 | InnoDB |
+---------------+------------+------------+---------+----------+---------+----------+--------+</pre>
<p><span style="font-weight: 400">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&nbsp; &nbsp; &nbsp; &nbsp; | size_in_mb |
+---------------+------------+-------------------+------------+
| myschema&nbsp; &nbsp; &nbsp; | mytable&nbsp; &nbsp; | idx_long_column &nbsp; | 1583538.95 |
| myschema&nbsp; &nbsp; &nbsp; | mytable&nbsp; &nbsp; | idx_short_column&nbsp; |&nbsp; 126432.98 |
| myschema&nbsp; &nbsp; &nbsp; | mytable&nbsp; &nbsp; | idx_short_col2&nbsp; &nbsp; |&nbsp; 122699.95 |
+---------------+------------+-------------------+------------+
3 rows in set (0.01 sec)</pre>
<p><span style="font-weight: 400">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 style="font-weight: 400">NOTE the huge index for a varchar(1000) that is ~1.5T in size.&nbsp;</span><span style="font-weight: 400">Maintaining such an index becomes increasingly expensive as the data size increases.</span></p>
<p><span style="font-weight: 400">The pt-online-schema-change had been running for ~8 days, and its latest estimate was 53 more days, which we can&rsquo;t afford, since the maximum value would be exceeded in ~15 days.&nbsp;</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">Copying `myschema`.`mytable`:&nbsp; 12% 53+16:48:01 remain
Copying `myschema`.`mytable`:&nbsp; 12% 53+16:48:30 remain
Copying `myschema`.`mytable`:&nbsp; 12% 53+16:48:59 remain
Copying `myschema`.`mytable`:&nbsp; 12% 53+16:49:26 remain
Copying `myschema`.`mytable`:&nbsp; 12% 53+16:49:53 remain
Copying `myschema`.`mytable`:&nbsp; 12% 53+16:50:19 remain
Copying `myschema`.`mytable`:&nbsp; 12% 53+16:50:49 remain
Copying `myschema`.`mytable`:&nbsp; 12% 53+16:51:17 remain
Copying `myschema`.`mytable`:&nbsp; 12% 53+16:51:45 remain</pre>
<p>&nbsp;</p>
<p><span style="font-weight: 400">So what do we do now?</span></p>
<p><span style="font-weight: 400">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 style="font-weight: 400">blue-green deployment</span></a><span style="font-weight: 400">.</span></p>
<p><span style="font-weight: 400">Then perform the direct ALTER on the green cluster. And finally, when ready, do the failover.</span></p>
<p>&nbsp;</p>
<p><span style="font-weight: 400">Sounds good, doesn&rsquo;t it?</span></p>
<p>&nbsp;</p>
<p><span style="font-weight: 400">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 style="font-weight: 400">&nbsp; parameter in its cluster parameter group to &ldquo;</span><i><span style="font-weight: 400">ALL_NON_LOSSY, ALL_UNSIGNED&rdquo;</span></i><span style="font-weight: 400"> in order to be able to replicate from an int unsigned column to a bigint unsigned column.</span></p>
<p><span style="font-weight: 400">So we tried that, it started too fast ~0.036% per minute, that&rsquo;s 2 days. That&rsquo;s great!</span></p>
<p><span style="font-weight: 400">We left the process running over the weekend, but we noticed it started to slow down again&hellip; By Monday, it was advancing at ~0.01% every 5 mins, which gives an ETA of 34 days.&nbsp;</span></p>
<p><strong>Why?&nbsp;</strong></p>
<p><span style="font-weight: 400">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.&nbsp;</span></p>
<p><span style="font-weight: 400">Again, unacceptable.</span></p>
<p><span style="font-weight: 400">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 style="font-weight: 400">Then we thought: What if we drop the secondary indexes, do the alter, and then add the indexes back?</span></p>
<p><span style="font-weight: 400">In theory, it should be faster, as:</span></p>
<ul>
<li style="font-weight: 400"><span style="font-weight: 400">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 style="font-weight: 400">ONLINE DDL</span></a><span style="font-weight: 400">.</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Altering the column datatype from INT to BIGINT is not an ONLINE operation, but the fact that it doesn&rsquo;t have to update secondary indexes during row copying to a new temporary table prevents the slowdown.</span><span style="font-weight: 400"><br>
</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Adding back the secondary indexes is an ONLINE DDL operation:</span></li>
</ul>
<p>&nbsp;</p>
<p><span style="font-weight: 400">&ldquo;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.&rdquo;</span></p>
<p><a href="https://dev.mysql.com/doc/refman/8.4/en/innodb-online-ddl-operations.html"><span style="font-weight: 400">https://dev.mysql.com/doc/refman/8.4/en/innodb-online-ddl-operations.html</span></a></p>
<p><span style="font-weight: 400">So let&rsquo;s do this:</span></p>
<p><span style="font-weight: 400">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&nbsp; Duplicates: 0&nbsp; Warnings: 0</pre>
<p>&nbsp;</p>
<p><span style="font-weight: 400">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&nbsp; Duplicates: 0&nbsp; Warnings: 0</pre>
<p>&nbsp;</p>
<p><span style="font-weight: 400">Looks very promising!!!</span></p>
<p>&nbsp;</p>
<p><span style="font-weight: 400">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>&nbsp;</p>
<p><b>Why?</b></p>
<p><span style="font-weight: 400">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 style="font-weight: 400">certain limits for the temporary space based on the instance type</span></a><span style="font-weight: 400">.&nbsp;</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 style="font-weight: 400">Even with a larger instance type, it&rsquo;s hard to create the 1.5T index without breaking open the piggy bank.</span></p>
<p>&nbsp;</p>
<p><b><i>Last resort</i></b><span style="font-weight: 400">, 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 style="font-weight: 400">Records: 4147498819&nbsp; Duplicates: 0&nbsp; Warnings: 0</span></pre>
<p>&nbsp;</p>
<p><span style="font-weight: 400">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&rsquo;t have the limitation of the temporary directory mentioned above.</span></p>
<p><span style="font-weight: 400">We were able to make it on time about 4 days before the auto_increment exhaustion, preventing downtime.</span></p>
<p>&nbsp;</p>
<p><span style="font-weight: 400">In retrospective we could have used the following approach to avoid the use of the blue/green deployment:</span></p>
<ol>
<li style="font-weight: 400"><span style="font-weight: 400">Perform a pt-online-schema-change on the main table, dropping the indexes, and changing the column type to bigint. ( with &ndash;no-swap-tables &ndash;no-drop-old-table &ndash;no-drop-new-table &ndash;no-drop-triggers).</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Add the secondary indexes using the direct alter with the COPY algorithm in the _new table.</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Once the alter finishes, swap the tables and drop the triggers.</span></li>
</ol>
<p>&nbsp;</p>
<h2><span style="font-weight: 400">Conclusion:</span><a class="anchor-link" id="conclusion"></a></h2>
<p><span style="font-weight: 400">What initially looked like an easy task with </span><a href="https://docs.percona.com/percona-toolkit/pt-online-schema-change.html"><span style="font-weight: 400">pt-online-schema-change</span></a><span style="font-weight: 400">, ended up being more complex.&nbsp;</span></p>
<p><span style="font-weight: 400">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&rsquo;s risk of downtime if it is not done on time.</span></p>
<p><span style="font-weight: 400">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 style="font-weight: 400">Percona Monitoring and Management</span></a><span style="font-weight: 400"> 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/">&lt;H1&gt; Run an ALTER TABLE for a huge table in Aurora</a> appeared first on <a href="https://www.percona.com">Percona</a>.</p>

<p>The post <a rel="nofollow" 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 rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Managing Valkey Cluster in Kubernetes</title>
      <link>https://www.percona.com/blog/managing-valkey-cluster-in-kubernetes/</link>
      <pubDate>Thu, 30 Apr 2026 23:05:39 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://www.percona.com/blog/">Blog - Percona</source>
      <description><![CDATA[<p>Over the last several years, Percona has introduced several rock-star Kubernetes Operators for managing MySQL, Percona XtraDB Cluster, MongoDB, and PostgreSQL. For Valkey, we are actively working with the community to contribute our knowledge, and experience to help brainstorm, develop, and test the official Valkey Operator for Kubernetes. While the Valkey Operator has not yet … Continued<br />
The post Managing Valkey Cluster in Kubernetes appeared first on Percona.</p>
<p>The post <a rel="nofollow" href="https://www.percona.com/blog/managing-valkey-cluster-in-kubernetes/">Managing Valkey Cluster in Kubernetes</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p><span style="font-weight: 400">Over the last several years, Percona has introduced several rock-star </span><a href="https://docs.percona.com/percona-operators"><span style="font-weight: 400">Kubernetes Operators</span></a><span style="font-weight: 400"> for managing MySQL, Percona XtraDB Cluster, MongoDB, and PostgreSQL. For Valkey, we are actively working with the community to contribute our knowledge, and experience to help brainstorm, develop, and test the official </span><a href="https://github.com/valkey-io/valkey-operator/"><span style="font-weight: 400">Valkey Operator for Kubernetes</span></a><span style="font-weight: 400">.</span></p>
<p><span style="font-weight: 400">While the <a href="https://github.com/valkey-io/valkey-operator">Valkey Operator</a> has not yet released a GA 1.0 version, we wanted to take this opportunity to highlight some recently added features.</span></p>
<h2><span style="font-weight: 400">Cluster Configuration</span><a class="anchor-link" id="cluster-configuration"></a></h2>
<p><span style="font-weight: 400">Up until recently, there was no native ability to provide configuration parameters to the Valkey server process running inside each deployed pod. This hurdle is now overcome, and you can supply configuration natively within the deployment CR.</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">apiVersion: valkey.io/v1alpha1
kind: ValkeyCluster
metadata:
&nbsp;&nbsp;name: my-valkey-cluster1
spec:
&nbsp;&nbsp;shards: 3
&nbsp;&nbsp;replicas: 1
&nbsp;&nbsp;config:
&nbsp;&nbsp;&nbsp;&nbsp;maxmemory: 500mb
&nbsp;&nbsp;&nbsp;&nbsp;maxmemory-policy: allkeys-lfu
&nbsp;&nbsp;&nbsp;&nbsp;maxclients: 5000
&nbsp;&nbsp;&nbsp;&nbsp;commandlog-execution-slower-than: 10000</pre>
<p><span style="font-weight: 400">For now, these parameters are set on initial cluster deployment. There is already </span><a href="https://github.com/valkey-io/valkey-operator/issues/141"><span style="font-weight: 400">traction underway</span></a><span style="font-weight: 400"> to allow certain parameters to be dynamically set at runtime. There are a small handful of certain cluster-based parameters that cannot be overridden by the user, otherwise it would break operator functionality.</span></p>
<h2><span style="font-weight: 400">User Access Control List (ACL)</span><a class="anchor-link" id="user-access-control-list-acl"></a></h2>
<p><span style="font-weight: 400">Managing users is always a tedious task for any database administrator. Creating ACLs for users in Valkey can be a bit confusing coming from a traditional RDBMS using GRANT syntax. To make things just a bit easier, Valkey Operator has added user permissions management to the deployment CR.</span></p>
<p><span style="font-weight: 400">Firstly, create your Secret containing usernames, and passwords:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">apiVersion: v1
kind: Secret
metadata:
&nbsp;&nbsp;name: valkey-cluster-sample-users
data:
&nbsp;&nbsp;alicepw: M21wdHlQQHNzdzByZA==
&nbsp;&nbsp;davidold: OVYqTHQlYXU4Mk5tdTlyeQ==
&nbsp;&nbsp;davidnew: VmFsa2V5I1J1bHojMjIzMw==</pre>
<p><span style="font-weight: 400">Next, deploy your cluster with users:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">apiVersion: valkey.io/v1alpha1
kind: ValkeyCluster
metadata:
&nbsp;&nbsp;name: my-cool-valkey-cluster
spec:
&nbsp;&nbsp;shards: 3
&nbsp;&nbsp;replicas: 1
&nbsp;&nbsp;users:
&nbsp;&nbsp;&nbsp;&nbsp;- name: alice
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;enabled: true
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;passwordSecret:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name: valkey-cluster-sample-users
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;keys: [alicepw]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;commands:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;allow: ["@read", "@write", "@connection"]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;deny: ["@admin", "@dangerous"]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;keys:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;readWrite: ["app:*", "cache:*"]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;readOnly: ["shared:*", "config:*"]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;writeOnly: ["logs:*", "metrics:*"]
&nbsp;&nbsp;&nbsp;&nbsp;- name: david
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;enabled: true
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;passwordSecret:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name: valkey-cluster-sample-users
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;keys:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- davidold
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- davidnew
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;commands:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;allow: ["@admin"]</pre>
<p><span style="font-weight: 400">There&rsquo;s quite a lot going on here. Let&rsquo;s break it down by first looking at the user &lsquo;alice&rsquo;:&nbsp;</span></p>
<p><span style="font-weight: 400">The &lsquo;alice&rsquo; user is enabled, with a password found in the referenced Secret and secret key. Next, we can see what commands, or in this case, command groups (Noted with &lsquo;@&rsquo;) that alice is allowed to execute, and which commands/groups are denied. Lastly, permissions on specific key patterns are identified for maximum security restrictions.</span></p>
<p><span style="font-weight: 400">The other user, &lsquo;david&rsquo;, can access all of the admin-group commands, and cannot read or write to any keys. Note that david&rsquo;s secret key reference is an array, which means you can provide multiple passwords per user; great for password rotation! Once david confirms the new password, the old password references can be removed from the CR and Secret, and the Valkey Operator will synchronize the ACLs.</span></p>
<p><span style="font-weight: 400">Users are dynamic, which means they can be added, removed, and modified without restarting the cluster.</span></p>
<h2><span style="font-weight: 400">TLS Support</span><a class="anchor-link" id="tls-support"></a></h2>
<p><span style="font-weight: 400">Bring on the encryption! TLS support was also recently added to the Valkey Operator. Create your Secret with the CA, TLS Key, and Cert files, and tell the CR where to find them:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">apiVersion: valkey.io/v1alpha1
kind: ValkeyCluster
metadata:
&nbsp;&nbsp;name: cluster-sample
spec:
&nbsp;&nbsp;shards: 3
&nbsp;&nbsp;replicas: 1
&nbsp;&nbsp;tls:
&nbsp;&nbsp;&nbsp;&nbsp;certificate:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;secretName: my-valkey-tls-secret</pre>
<p><span style="font-weight: 400">Once deployed, the Valkey operator will mount the referenced secret to each pod, and add all the proper configuration parameters. By doing so, the operator enforces SSL/TLS communication between each Valkey cluster node, securing node-to-node, and replication traffic within your kubernetes network. Additionally, by creating user certificates signed by the same CA, traffic between your clients, and the Valkey clusters nodes is secured. This configuration is BYOC (bring-your-own-certificate), which works well with the popular CertManager, or other certificate authority you may be using.</span></p>
<h2><span style="font-weight: 400">On The Horizon</span><a class="anchor-link" id="on-the-horizon"></a></h2>
<p><span style="font-weight: 400">As a teaser, here are a couple other features coming soon to Valkey Operator:</span></p>
<ul>
<li style="font-weight: 400"><a href="https://valkey.io/topics/persistence/"><span style="font-weight: 400">Data Persistence</span></a><span style="font-weight: 400">: The ability to enable background snapshots of the in-memory dataset for backup, and recovery. Additionally, supporting the AOF (append-only file) for streaming changes.</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Simple Replication: The operator currently only supports Valkey in </span><a href="https://valkey.io/topics/cluster-tutorial/"><span style="font-weight: 400">cluster mode</span></a><span style="font-weight: 400">. Be on the lookout for traditional primary -&gt; N-replica configurations, along with Sentinel monitoring.</span></li>
</ul>
<h2><span style="font-weight: 400">Join Us</span><a class="anchor-link" id="join-us"></a></h2>
<p><span style="font-weight: 400">Want to contribute to the Valkey Operator? Join any of the discussions/</span><a href="https://github.com/valkey-io/valkey-operator/issues"><span style="font-weight: 400">issues</span></a><span style="font-weight: 400"> on our github, or come introduce yourself in the </span><a href="https://valkey.io/slack"><span style="font-weight: 400">Valkey Slack</span></a><span style="font-weight: 400"> community.</span></p>
<p>The post <a href="https://www.percona.com/blog/managing-valkey-cluster-in-kubernetes/">Managing Valkey Cluster in Kubernetes</a> appeared first on <a href="https://www.percona.com">Percona</a>.</p>

<p>The post <a rel="nofollow" href="https://www.percona.com/blog/managing-valkey-cluster-in-kubernetes/">Managing Valkey Cluster in Kubernetes</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Open source doesn’t die. It gets unfunded.</title>
      <link>https://percona.community/blog/2026/04/30/open-source-doesnt-die.-it-gets-unfunded./</link>
      <pubDate>Thu, 30 Apr 2026 11:00:00 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://percona.community/blog/">Percona Community Blog - learn about MySQL, MariaDB, PostgreSQL, and MongoDB</source>
      <description><![CDATA[<p>If you are using PostgreSQL in any capacity very likely this week has started for you with a bang. pgBackRest, one of the most known tools for PostgreSQL, praised for the scalable and reliable way to do backups has announced that the project is currently archived.</p>
<p>The post <a rel="nofollow" href="https://percona.community/blog/2026/04/30/open-source-doesnt-die.-it-gets-unfunded./">Open source doesn’t die. It gets unfunded.</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>If you are using PostgreSQL in any capacity very likely this week has started for you with a bang. pgBackRest, one of the most known tools for PostgreSQL, praised for the scalable and reliable way to do backups has announced that the project is currently archived.</p>
<h2 id="archived-you-mean-eol">Archived, <a href="https://www.reddit.com/r/PostgreSQL/comments/1sx2ttg/comment/oilzdag/?utm_source=share&amp;utm_medium=web3x&amp;utm_name=web3xcss&amp;utm_term=1&amp;utm_content=share_button" target="_blank" rel="noopener noreferrer">you mean EOL</a>?<a class="anchor-link" id="archived-you-mean-eol"></a></h2>
<p><figure>
<img decoding="async" src="https://percona.community/blog/2026/04/opensourcedoesntdie-reddit.png" alt="blog/2026/04/opensourcedoesntdie-reddit.png"></figure>
</p>
<p>No! Open source software rarely has a hard &ldquo;end of life.&rdquo; What it does have are maintainership gaps and those can be just as serious.</p>
<p>It&rsquo;s different when PostgreSQL community announces a major version EOL. This happens because Community chooses to not to support it and move on to focus on newer versions.</p>
<p><figure>
<img decoding="async" src="https://percona.community/blog/2026/04/opensourcedoesntdie-thisisopensource.png" alt="blog/2026/04/opensourcedoesntdie-thisisopensource.png"></figure>
</p>
<p>Reading the message from David Steele, the long-time primary maintainer of pgBackRest you will not find &ldquo;end of life&rdquo; term. The project is marked read-only and no longer actively maintained, but that is not the same as being permanently dead.</p>
<p><figure>
<img decoding="async" src="https://percona.community/blog/2026/04/opensourcedoesntdie-maintenance.png" alt="blog/2026/04/opensourcedoesntdie-maintenance.png"></figure>
</p>
<p>pgBackRest is not &ldquo;end of life.&rdquo; There is no governing body declaring support ended. What happened is simpler and more common in open source: the maintainer can no longer afford to continue.</p>
<h2 id="so-what-happened-then">So what happened then?<a class="anchor-link" id="so-what-happened-then"></a></h2>
<p>This requires some story telling and I don&rsquo;t think that I can do it better than <a href="https://mydbanotebook.org/about/" target="_blank" rel="noopener noreferrer">L&aelig;titia Avrot</a> already did in her <a href="https://mydbanotebook.org/posts/pgbackrest-is-dead.-now-what/#what-happened" target="_blank" rel="noopener noreferrer">blogpost</a> (though I do not like the title):</p>
<blockquote>
<p>Crunchy Data, which had sponsored&nbsp;<code>pgBackRest</code>&nbsp;for most of its life and employed David, was sold. After that, David spent months looking for a position that would let him keep working on the project. He also tried to secure independent sponsorship. Neither worked out. He needs to make a living. The project requires sustained effort which he can no longer provide without being paid for it.</p>
</blockquote>
<p>This is the issue. An experienced developer, who wants to work on the project (that a big chunk of enterprises use) finds himself to be the &ldquo;Nebraska guy&rdquo; from <a href="https://xkcd.com/2347/" target="_blank" rel="noopener noreferrer">XKCD comic</a>.</p>
<p>When you look at the situation we&rsquo;re in this is the classic &ldquo;Nebraska guy problem&rdquo;: critical infrastructure maintained by a single person. pgBackRest is widely used in production, yet its sustainability dependson one individual being able to justify working on it. That does not seem fair and David did right to point this out with his move.</p>
<p>Of course, if anyone in the community chose to, they can still maintain the project by forking it. But why, since the problem is elsewhere?</p>
<p>Most people understand that engineers need to be paid for their work. What not everyone realizes is that the free for all software that the open source license provides does not mean free as in beer. Someone still needs to fund it!</p>
<p>Unfortunately &ldquo;someone&rdquo; almost certainly is going to be &ldquo;no-one&rdquo; unless &ldquo;anyone&rdquo; realizes they are going to miss the software if nobody maintains it anymore.</p>
<p>While there&rsquo;s a claim to be made that:</p>
<blockquote>
<p>Companies are as good as they have to and as bad as they are allowed to</p>
</blockquote>
<p>And often we see that an entity uses software they do not have to pay license fees for, treating this as cost optimization. There is also a large chunk of organizations that realize this is not a good long term strategy. Actively lowering the operational risk is important.</p>
<p>This is where foundations typically kick in: providing an easy way for organizations to contribute and ensure the longevity and healthiness of the projects. But PostgreSQL does not (yet) have one.</p>
<h2 id="where-are-we-now">Where are we now?<a class="anchor-link" id="where-are-we-now"></a></h2>
<p>There&rsquo;s a lot of backchannel talks happening.</p>
<p>Join the ones on:</p>
<ul>
<li>Telegram</li>
<li>Discord</li>
<li>Slack</li>
<li><a href="https://www.reddit.com/r/PostgreSQL/comments/1sx2ttg/pgbackrest_is_no_longer_being_maintained/" target="_blank" rel="noopener noreferrer">Reddit</a> (I don&rsquo;t have enough karma to engage there :/)</li>
</ul>
<p>or let us know what is your stance <a href="https://forums.percona.com/t/pgbackrest-is-eol/40720" target="_blank" rel="noopener noreferrer">(Percona Community Forum thread available)</a> so that we can represent you in the discussions we are having.</p>
<p>A lot of blog posts have been written on this subject, check out <a href="https://planet.postgresql.org/" target="_blank" rel="noopener noreferrer">Planet PostgreSQL</a> to find some of them! I particularly enjoyed some of them, the <a href="https://proopensource.it/blog/postgresql-ecosystem-problems-2026" target="_blank" rel="noopener noreferrer">one</a> from <a href="https://proopensource.it/stefanie-janine-stoelting.html" target="_blank" rel="noopener noreferrer">Stefanie Janine St&ouml;lting</a>, I feel I am mostly aligned with. PostgreSQL needs an Ecosystem Umbrella Foundation</p>
<h2 id="the-future-of-open-source-is-on-us">The future of open source is on us<a class="anchor-link" id="the-future-of-open-source-is-on-us"></a></h2>
<p>Reading that a project is EOL is triggering to me. When long-time maintainer announced plans to step away after more than a decade of work, instead of focusing on what the problem is that caused him to do so and how to solve the issue.Naming it &ldquo;dead&rdquo; complicate things even further. Labeling the project as &ldquo;dead&rdquo; doesn&rsquo;t solve the problem. Rather, it accelerates the wrong response. Users start looking for replacements instead of asking how to sustain the project.</p>
<p>This is not the way, young Padawan!</p>
<p><figure>
<img decoding="async" src="https://percona.community/blog/2026/04/opensourcedoesntdie-youngpadawan.png" alt="blog/2026/04/opensourcedoesntdie-youngpadawan.png"></figure>
</p>
<p>We need a body that helps both users and authors by:</p>
<ol>
<li>Providing governance and a helping hand to the ecosystem. Yes, this is also funding</li>
<li>Providing guarantees of healthiness. This means users will have it easier to know the tools are in good shape.</li>
</ol>
<h2 id="so-whats-with-pgbackrest">So what&rsquo;s with pgBackRest<a class="anchor-link" id="so-whats-with-pgbackrest"></a></h2>
<p>While we talk here in the public, a lot of decisions are being made and Percona among other companies is working towards resolving this situation.</p>
<p><figure>
<img decoding="async" src="https://percona.community/blog/2026/04/opensourcedoesntdie-allyouneed.png" alt="blog/2026/04/opensourcedoesntdie-allyouneed.png"></figure>
</p>
<p>Have patience. Work is already underway behind the scenes, and the situation is evolving. There will be positive news resolving the situation coming soon, as Open Source doesn&rsquo;t die!</p>

<p>The post <a rel="nofollow" href="https://percona.community/blog/2026/04/30/open-source-doesnt-die.-it-gets-unfunded./">Open source doesn’t die. It gets unfunded.</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Open source doesn’t die. It gets unfunded.</title>
      <link>https://percona.community/blog/2026/04/30/open-source-doesnt-die-it-gets-unfunded/</link>
      <pubDate>Thu, 30 Apr 2026 11:00:00 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://percona.community/blog/">Percona Community Blog - learn about MySQL, MariaDB, PostgreSQL, and MongoDB</source>
      <description><![CDATA[<p>If you are using PostgreSQL in any capacity very likely this week has started for you with a bang. pgBackRest, one of the most known tools for PostgreSQL, praised for the scalable and reliable way to do backups has announced that the project is currently archived.</p>
<p>The post <a rel="nofollow" href="https://percona.community/blog/2026/04/30/open-source-doesnt-die-it-gets-unfunded/">Open source doesn’t die. It gets unfunded.</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>If you are using PostgreSQL in any capacity very likely this week has started for you with a bang. pgBackRest, one of the most known tools for PostgreSQL, praised for the scalable and reliable way to do backups has announced that the project is currently archived.</p>
<h2 id="archived-you-mean-eol">Archived, <a href="https://www.reddit.com/r/PostgreSQL/comments/1sx2ttg/comment/oilzdag/?utm_source=share&amp;utm_medium=web3x&amp;utm_name=web3xcss&amp;utm_term=1&amp;utm_content=share_button" target="_blank" rel="noopener noreferrer">you mean EOL</a>?<a class="anchor-link" id="archived-you-mean-eol"></a></h2>
<p><figure>
<img decoding="async" src="https://percona.community/blog/2026/04/opensourcedoesntdie-reddit.png" alt="blog/2026/04/opensourcedoesntdie-reddit.png"></figure>
</p>
<p>No! Open source software rarely has a hard &ldquo;end of life.&rdquo; What it does have are maintainership gaps and those can be just as serious.</p>
<p>It&rsquo;s different when PostgreSQL community announces a major version EOL. This happens because Community chooses to not to support it and move on to focus on newer versions.</p>
<p><figure>
<img decoding="async" src="https://percona.community/blog/2026/04/opensourcedoesntdie-thisisopensource.png" alt="blog/2026/04/opensourcedoesntdie-thisisopensource.png"></figure>
</p>
<p>Reading the message from David Steele, the long-time primary maintainer of pgBackRest you will not find &ldquo;end of life&rdquo; term. The project is marked read-only and no longer actively maintained, but that is not the same as being permanently dead.</p>
<p><figure>
<img decoding="async" src="https://percona.community/blog/2026/04/opensourcedoesntdie-maintenance.png" alt="blog/2026/04/opensourcedoesntdie-maintenance.png"></figure>
</p>
<p>pgBackRest is not &ldquo;end of life.&rdquo; There is no governing body declaring support ended. What happened is simpler and more common in open source: the maintainer can no longer afford to continue.</p>
<h2 id="so-what-happened-then">So what happened then?<a class="anchor-link" id="so-what-happened-then"></a></h2>
<p>This requires some story telling and I don&rsquo;t think that I can do it better than <a href="https://mydbanotebook.org/about/" target="_blank" rel="noopener noreferrer">L&aelig;titia Avrot</a> already did in her <a href="https://mydbanotebook.org/posts/pgbackrest-is-dead.-now-what/#what-happened" target="_blank" rel="noopener noreferrer">blogpost</a> (though I do not like the title):</p>
<blockquote>
<p>Crunchy Data, which had sponsored&nbsp;<code>pgBackRest</code>&nbsp;for most of its life and employed David, was sold. After that, David spent months looking for a position that would let him keep working on the project. He also tried to secure independent sponsorship. Neither worked out. He needs to make a living. The project requires sustained effort which he can no longer provide without being paid for it.</p>
</blockquote>
<p>This is the issue. An experienced developer, who wants to work on the project (that a big chunk of enterprises use) finds himself to be the &ldquo;Nebraska guy&rdquo; from <a href="https://xkcd.com/2347/" target="_blank" rel="noopener noreferrer">XKCD comic</a>.</p>
<p>When you look at the situation we&rsquo;re in this is the classic &ldquo;Nebraska guy problem&rdquo;: critical infrastructure maintained by a single person. pgBackRest is widely used in production, yet its sustainability dependson one individual being able to justify working on it. That does not seem fair and David did right to point this out with his move.</p>
<p>Of course, if anyone in the community chose to, they can still maintain the project by forking it. But why, since the problem is elsewhere?</p>
<p>Most people understand that engineers need to be paid for their work. What not everyone realizes is that the free for all software that the open source license provides does not mean free as in beer. Someone still needs to fund it!</p>
<p>Unfortunately &ldquo;someone&rdquo; almost certainly is going to be &ldquo;no-one&rdquo; unless &ldquo;anyone&rdquo; realizes they are going to miss the software if nobody maintains it anymore.</p>
<p>While there&rsquo;s a claim to be made that:</p>
<blockquote>
<p>Companies are as good as they have to and as bad as they are allowed to</p>
</blockquote>
<p>And often we see that an entity uses software they do not have to pay license fees for, treating this as cost optimization. There is also a large chunk of organizations that realize this is not a good long term strategy. Actively lowering the operational risk is important.</p>
<p>This is where foundations typically kick in: providing an easy way for organizations to contribute and ensure the longevity and healthiness of the projects. But PostgreSQL does not (yet) have one.</p>
<h2 id="where-are-we-now">Where are we now?<a class="anchor-link" id="where-are-we-now"></a></h2>
<p>There&rsquo;s a lot of backchannel talks happening.</p>
<p>Join the ones on:</p>
<ul>
<li>Telegram</li>
<li>Discord</li>
<li>Slack</li>
<li><a href="https://www.reddit.com/r/PostgreSQL/comments/1sx2ttg/pgbackrest_is_no_longer_being_maintained/" target="_blank" rel="noopener noreferrer">Reddit</a> (I don&rsquo;t have enough karma to engage there :/)</li>
</ul>
<p>or let us know what is your stance <a href="https://forums.percona.com/t/pgbackrest-is-eol/40720" target="_blank" rel="noopener noreferrer">(Percona Community Forum thread available)</a> so that we can represent you in the discussions we are having.</p>
<p>A lot of blog posts have been written on this subject, check out <a href="https://planet.postgresql.org/" target="_blank" rel="noopener noreferrer">Planet PostgreSQL</a> to find some of them! I particularly enjoyed some of them, the <a href="https://proopensource.it/blog/postgresql-ecosystem-problems-2026" target="_blank" rel="noopener noreferrer">one</a> from <a href="https://proopensource.it/stefanie-janine-stoelting.html" target="_blank" rel="noopener noreferrer">Stefanie Janine St&ouml;lting</a>, I feel I am mostly aligned with. PostgreSQL needs an Ecosystem Umbrella Foundation</p>
<h2 id="the-future-of-open-source-is-on-us">The future of open source is on us<a class="anchor-link" id="the-future-of-open-source-is-on-us"></a></h2>
<p>Reading that a project is EOL is triggering to me. When long-time maintainer announced plans to step away after more than a decade of work, instead of focusing on what the problem is that caused him to do so and how to solve the issue.Naming it &ldquo;dead&rdquo; complicate things even further. Labeling the project as &ldquo;dead&rdquo; doesn&rsquo;t solve the problem. Rather, it accelerates the wrong response. Users start looking for replacements instead of asking how to sustain the project.</p>
<p>This is not the way, young Padawan!</p>
<p><figure>
<img decoding="async" src="https://percona.community/blog/2026/04/opensourcedoesntdie-youngpadawan.png" alt="blog/2026/04/opensourcedoesntdie-youngpadawan.png"></figure>
</p>
<p>We need a body that helps both users and authors by:</p>
<ol>
<li>Providing governance and a helping hand to the ecosystem. Yes, this is also funding</li>
<li>Providing guarantees of healthiness. This means users will have it easier to know the tools are in good shape.</li>
</ol>
<h2 id="so-whats-with-pgbackrest">So what&rsquo;s with pgBackRest<a class="anchor-link" id="so-whats-with-pgbackrest"></a></h2>
<p>While we talk here in the public, a lot of decisions are being made and Percona among other companies is working towards resolving this situation.</p>
<p><figure>
<img decoding="async" src="https://percona.community/blog/2026/04/opensourcedoesntdie-allyouneed.png" alt="blog/2026/04/opensourcedoesntdie-allyouneed.png"></figure>
</p>
<p>Have patience. Work is already underway behind the scenes, and the situation is evolving. There will be positive news resolving the situation coming soon, as Open Source doesn&rsquo;t die!</p>

<p>The post <a rel="nofollow" href="https://percona.community/blog/2026/04/30/open-source-doesnt-die-it-gets-unfunded/">Open source doesn’t die. It gets unfunded.</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Continued Commitment to Percona XtraDB Cluster</title>
      <link>https://www.percona.com/blog/continued-commitment-to-percona-xtradb-cluster/</link>
      <pubDate>Thu, 30 Apr 2026 09:53:09 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://www.percona.com/blog/">Blog - Percona</source>
      <description><![CDATA[<p>At Percona, our priority has always been to provide the open source database solutions that our users can count on for the long term. Percona XtraDB Cluster (PXC) is a core part of that promise, delivering the high availability, scalability, and data integrity that mission-critical MySQL deployments depend on. MariaDB has announced that September 30, … Continued<br />
The post Continued Commitment to Percona XtraDB Cluster appeared first on Percona.</p>
<p>The post <a rel="nofollow" href="https://www.percona.com/blog/continued-commitment-to-percona-xtradb-cluster/">Continued Commitment to Percona XtraDB Cluster</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>At Percona, our priority has always been to provide the open source database solutions that our users can count on for the long term. Percona XtraDB Cluster (PXC) is a core part of that promise, delivering the high availability, scalability, and data integrity that mission-critical MySQL deployments depend on.</p>
<p>MariaDB has announced that September 30, 2026 will be the end-of-life date for continued maintenance and regular binary releases of MySQL Galera Cluster. We want to be clear about what this means for the organizations that rely on PXC: nothing is changing. Our commitment to PXC and the community that runs it is as strong as ever.</p>
<p>What is ending upstream is precisely what we already have in place. For anyone looking for an alternative path forward, PXC is the natural place to land.</p>
<h4>What PXC users can count on</h4>
<ul>
<li><strong>Our open Galera fork</strong>: Percona maintains its <a href="https://github.com/percona/galera/tree/4.x-8.0" target="_blank" rel="noopener">own Galera repository</a>, open today and staying that way. We track upstream Galera releases, carry the fixes our customers need, and keep the codebase fully available for the community. PXC is built on this work, on terms we control.</li>
<li><strong>Regular releases at the current cadence</strong>: Binary releases, bug fixes, and security patches continue to ship on the same terms and schedule our users have come to expect. You can review our full <a href="https://docs.percona.com/percona-xtradb-cluster/" target="_blank" rel="noopener">release history and release notes</a> on the Percona documentation site.</li>
<li><strong>Long-term support</strong>: PXC remains fully supported under our existing long-term support terms. If your organization is planning three to five years ahead, PXC is a safe foundation for those plans.</li>
<li><strong>Compatibility and ecosystem integration</strong>: Strong binary compatibility with MySQL and Percona Server for MySQL, tight integration with Percona XtraBackup and Percona Monitoring and Management, and continued support across Kubernetes and traditional deployment environments.</li>
</ul>
<h4>What we&rsquo;re continuing to invest in</h4>
<p>Our engineering teams remain committed to making PXC better, focused on the things that make it a trusted choice: performance, stability, security, and a smooth operator experience. That work continues at pace. The PXC you depend on today will keep getting better, and the PXC you are evaluating for tomorrow will be ready when you need it.</p>
<h2>Talk to us<a class="anchor-link" id="talk-to-us"></a></h2>
<p>If you have specific questions about your PXC deployment, your upgrade path, or your long-term high availability strategy, we&rsquo;d love to hear from you. Reach out to your Percona contact, post a question in the <a href="https://forums.percona.com" target="_blank" rel="noopener">Percona community forums</a>, or connect with our team directly. High availability is too important to leave to uncertainty, and we are here to make sure you have the clarity and the support you need.</p>
<p><!-- notionvc: f139f266-790e-4b33-b8a5-96be27606c4a --></p>
<p>The post <a href="https://www.percona.com/blog/continued-commitment-to-percona-xtradb-cluster/">Continued Commitment to Percona XtraDB Cluster</a> appeared first on <a href="https://www.percona.com">Percona</a>.</p>

<p>The post <a rel="nofollow" href="https://www.percona.com/blog/continued-commitment-to-percona-xtradb-cluster/">Continued Commitment to Percona XtraDB Cluster</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>From Ecosystem to Architecture: Expanding How We Look at MariaDB</title>
      <link>https://mariadb.org/from-ecosystem-to-architecture-expanding-how-we-look-at-mariadb/</link>
      <pubDate>Thu, 30 Apr 2026 07:46:58 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.org/">MariaDB.org</source>
      <description><![CDATA[<p>Over the past month, one question has been coming up with increasing frequency:<br />
What is the MySQL / MariaDB ecosystem?<br />
In most discussions, the answer tends to focus on contributors to the source code: engineers, committers, and core developers shaping the database itself. …<br />
Continue reading \"From Ecosystem to Architecture: Expanding How We Look at MariaDB\"<br />
The post From Ecosystem to Architecture: Expanding How We Look at MariaDB appeared first on MariaDB.org.</p>
<p>The post <a rel="nofollow" href="https://mariadb.org/from-ecosystem-to-architecture-expanding-how-we-look-at-mariadb/">From Ecosystem to Architecture: Expanding How We Look at MariaDB</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>Over the past month, one question has been coming up with increasing frequency:<br>
What is the MySQL / MariaDB ecosystem?<br>
In most discussions, the answer tends to focus on contributors to the source code: engineers, committers, and core developers shaping the database itself. &hellip; </p>
<p class="link-more"><a href="https://mariadb.org/from-ecosystem-to-architecture-expanding-how-we-look-at-mariadb/" class="more-link">Continue reading<span class="screen-reader-text"> &ldquo;From Ecosystem to Architecture: Expanding How We Look at MariaDB&rdquo;</span></a></p>
<p>The post <a rel="nofollow" href="https://mariadb.org/from-ecosystem-to-architecture-expanding-how-we-look-at-mariadb/">From Ecosystem to Architecture: Expanding How We Look at MariaDB</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>

<p>The post <a rel="nofollow" href="https://mariadb.org/from-ecosystem-to-architecture-expanding-how-we-look-at-mariadb/">From Ecosystem to Architecture: Expanding How We Look at MariaDB</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Adding a New Data Type to MariaDB with Type_handler – Part 1</title>
      <link>https://mariadb.org/adding-a-new-data-type-to-mariadb-with-type_handler-part-1/</link>
      <pubDate>Thu, 30 Apr 2026 06:12:31 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.org/">MariaDB.org</source>
      <description><![CDATA[<p>This is the first part of the series about how to add a new data type to MariaDB using the Type_handler framework. A preliminary article has already been published to start the series; …<br />
Continue reading \"Adding a New Data Type to MariaDB with Type_handler – Part 1\"<br />
The post Adding a New Data Type to MariaDB with Type_handler – Part 1 appeared first on MariaDB.org.</p>
<p>The post <a rel="nofollow" href="https://mariadb.org/adding-a-new-data-type-to-mariadb-with-type_handler-part-1/">Adding a New Data Type to MariaDB with Type_handler – Part 1</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>This is the first part of the series about how to add a new data type to MariaDB using the Type_handler framework. A preliminary article has already been published to start the series; &hellip; </p>
<p class="link-more"><a href="https://mariadb.org/adding-a-new-data-type-to-mariadb-with-type_handler-part-1/" class="more-link">Continue reading<span class="screen-reader-text"> &ldquo;Adding a New Data Type to MariaDB with Type_handler &ndash; Part 1&rdquo;</span></a></p>
<p>The post <a rel="nofollow" href="https://mariadb.org/adding-a-new-data-type-to-mariadb-with-type_handler-part-1/">Adding a New Data Type to MariaDB with Type_handler &ndash; Part 1</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>

<p>The post <a rel="nofollow" href="https://mariadb.org/adding-a-new-data-type-to-mariadb-with-type_handler-part-1/">Adding a New Data Type to MariaDB with Type_handler – Part 1</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Troubleshooting logical replication delay made easy</title>
      <link>https://www.percona.com/blog/troubleshooting-logical-replication-delay-made-easy/</link>
      <pubDate>Thu, 30 Apr 2026 04:57:02 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://www.percona.com/blog/">Blog - Percona</source>
      <description><![CDATA[<p>This blog is based on a real production case in which users experienced a serious delay in logical replication. Let me try to explain how to approach similar cases and analyze them in an easy method, because lag in logical replication is a common problem, and we should expect it to come up for different … Continued<br />
The post Troubleshooting logical replication delay made easy appeared first on Percona.</p>
<p>The post <a rel="nofollow" href="https://www.percona.com/blog/troubleshooting-logical-replication-delay-made-easy/">Troubleshooting logical replication delay made easy</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>This blog is based on a real production case in which users experienced a serious delay in logical replication. Let me try to explain how to approach similar cases and analyze them in an easy method, because lag in logical replication is a common problem, and we should expect it to come up for different environments. But sometimes troubleshooting can be challenging, especially on DBaaS environments where we won&rsquo;t get in-depth information at OS / hardware level. Such situations force us to deal with limited information which is available <b>within the PostgreSQL connection</b> (No host-level troubleshooting possible)</p>
<h2>The Case<a class="anchor-link" id="the-case"></a></h2>
<p>The case that triggered this blog was an attempt to migrate from one cloud vendor, to a recent version of PostgreSQL on a DBaaS offering of another cloud vendor. They started observing huge replication lag and reported to Percona. As usual, we started with pg_gather data collection.</p>
<p>(At Percona, we use pg_gather for diagnosis. Even though this blog and diagnosis refers to pg_gather report, any good diagnosis tool / scripts which can help to study the wait-event pattern and lag details could be able to help)</p>
<p><img decoding="async" loading="lazy" class="alignnone size-full wp-image-45287" src="https://www.percona.com/wp-content/uploads/2026/04/CaseLogicalLag.png" alt="" width="1276" height="227"></p>
<p>We saw upto 4.5 terabyte lag is happening at the transmission side (Publisher) on the customer case. The <b>&ldquo;Transmission&rdquo;&nbsp; lag&rdquo; is the difference between the latest generated LSN and the LSN which the WAL Sender is able to send (sent_lsn of pg_stat_replication)</b>. That&rsquo;s a first indication that the problem is mainly at the publisher side (WAL Sender) and it is not able to send the information fast enough.</p>
<p>Next step of investigation is to understand what both those WAL Senders might be doing. The wait event information for each WAL Sender could provide a clear clue on where the delay is happening.</p>
<p><img decoding="async" loading="lazy" class="alignnone size-full wp-image-45288" src="https://www.percona.com/wp-content/uploads/2026/04/CaseLogicalLagWait.png" alt="" width="572" height="131"></p>
<p>Both the WAL Senders are mainly waiting in &ldquo;<b>WalSenderWriteData</b>&rdquo; event upto 85% of its time. This is a very unusual level of wait.</p>
<p>Following is the logic behind this.</p>
<ol>
<li>Logical decoding hands a finished record to<br>
			<span id="urvanov-syntax-highlighter-69f2e2a30d6d9416087273" class="urvanov-syntax-highlighter-syntax urvanov-syntax-highlighter-syntax-inline  crayon-theme-classic crayon-theme-classic-inline urvanov-syntax-highlighter-font-monaco" style="font-size: 12px !important;line-height: 15px !important;font-size: 12px !important"><span class="crayon-pre urvanov-syntax-highlighter-code" style="font-size: 12px !important;line-height: 15px !important;font-size: 12px !important"><span class="crayon-e">WalSndWriteData</span><span class="crayon-sy">(</span><span class="crayon-sy">)</span></span></span></li>
<li>The data is queued in the<br>
			<span id="urvanov-syntax-highlighter-69f2e2a30d6e1854553405" class="urvanov-syntax-highlighter-syntax urvanov-syntax-highlighter-syntax-inline  crayon-theme-classic crayon-theme-classic-inline urvanov-syntax-highlighter-font-monaco" style="font-size: 12px !important;line-height: 15px !important;font-size: 12px !important"><span class="crayon-pre urvanov-syntax-highlighter-code" style="font-size: 12px !important;line-height: 15px !important;font-size: 12px !important"><span class="crayon-v">libpq</span></span></span>&nbsp; send buffer with<br>
			<span id="urvanov-syntax-highlighter-69f2e2a30d6e3649420448" class="urvanov-syntax-highlighter-syntax urvanov-syntax-highlighter-syntax-inline  crayon-theme-classic crayon-theme-classic-inline urvanov-syntax-highlighter-font-monaco" style="font-size: 12px !important;line-height: 15px !important;font-size: 12px !important"><span class="crayon-pre urvanov-syntax-highlighter-code" style="font-size: 12px !important;line-height: 15px !important;font-size: 12px !important"><span class="crayon-v">pq_putmessage_noblock</span></span></span></li>
<li>A non-blocking flush is attempted with<br>
			<span id="urvanov-syntax-highlighter-69f2e2a30d6e5548818300" class="urvanov-syntax-highlighter-syntax urvanov-syntax-highlighter-syntax-inline  crayon-theme-classic crayon-theme-classic-inline urvanov-syntax-highlighter-font-monaco" style="font-size: 12px !important;line-height: 15px !important;font-size: 12px !important"><span class="crayon-pre urvanov-syntax-highlighter-code" style="font-size: 12px !important;line-height: 15px !important;font-size: 12px !important"><span class="crayon-e">pq_flush_if_writable</span><span class="crayon-sy">(</span><span class="crayon-sy">)</span></span></span>&nbsp;.&nbsp; But when the kernel send buffer is full, internal_flush_buffer() returns 0 with <b>EAGAIN / EWOULDBLOCK</b>&nbsp; and data stays buffered &mdash;<br>
			<span id="urvanov-syntax-highlighter-69f2e2a30d6e7107501997" class="urvanov-syntax-highlighter-syntax urvanov-syntax-highlighter-syntax-inline  crayon-theme-classic crayon-theme-classic-inline urvanov-syntax-highlighter-font-monaco" style="font-size: 12px !important;line-height: 15px !important;font-size: 12px !important"><span class="crayon-pre urvanov-syntax-highlighter-code" style="font-size: 12px !important;line-height: 15px !important;font-size: 12px !important"><span class="crayon-e">pq_is_send_pending</span><span class="crayon-sy">(</span><span class="crayon-sy">)</span></span></span>&nbsp; becomes<br>
			<span id="urvanov-syntax-highlighter-69f2e2a30d6e9747931880" class="urvanov-syntax-highlighter-syntax urvanov-syntax-highlighter-syntax-inline  crayon-theme-classic crayon-theme-classic-inline urvanov-syntax-highlighter-font-monaco" style="font-size: 12px !important;line-height: 15px !important;font-size: 12px !important"><span class="crayon-pre urvanov-syntax-highlighter-code" style="font-size: 12px !important;line-height: 15px !important;font-size: 12px !important"><span class="crayon-t">true</span></span></span></li>
<li>The fast-path return is skipped, so it enters<br>
			<span id="urvanov-syntax-highlighter-69f2e2a30d6eb288901571" class="urvanov-syntax-highlighter-syntax urvanov-syntax-highlighter-syntax-inline  crayon-theme-classic crayon-theme-classic-inline urvanov-syntax-highlighter-font-monaco" style="font-size: 12px !important;line-height: 15px !important;font-size: 12px !important"><span class="crayon-pre urvanov-syntax-highlighter-code" style="font-size: 12px !important;line-height: 15px !important;font-size: 12px !important"><span class="crayon-e">ProcessPendingWrites</span><span class="crayon-sy">(</span><span class="crayon-sy">)</span></span></span></li>
<li>There,<br>
			<span id="urvanov-syntax-highlighter-69f2e2a30d6ec235984838" class="urvanov-syntax-highlighter-syntax urvanov-syntax-highlighter-syntax-inline  crayon-theme-classic crayon-theme-classic-inline urvanov-syntax-highlighter-font-monaco" style="font-size: 12px !important;line-height: 15px !important;font-size: 12px !important"><span class="crayon-pre urvanov-syntax-highlighter-code" style="font-size: 12px !important;line-height: 15px !important;font-size: 12px !important"><span class="crayon-e">WalSndWait</span><span class="crayon-sy">(</span><span class="crayon-v">WL_SOCKET_WRITEABLE</span><span class="crayon-h"> </span><span class="crayon-o">|</span><span class="crayon-h"> </span><span class="crayon-v">WL_SOCKET_READABLE</span><span class="crayon-sy">,</span><span class="crayon-h"> </span><span class="crayon-v">sleeptime</span><span class="crayon-sy">,</span><span class="crayon-h"> </span><span class="crayon-v">WAIT_EVENT_WAL_SENDER_WRITE_DATA</span><span class="crayon-sy">)</span></span></span>&nbsp; blocks until the socket is writable again or the subscriber sends a reply &mdash; that wait is what shows up as wait-event <b>WalSenderWriteData</b></li>
</ol>
<p>Source code reference : <a href="https://github.com/postgres/postgres/blob/master/src/backend/replication/walsender.c#L1673">src/backend/replication/walsender.c</a></p>
<p>Which means that this wait event could happen due to the following reasons which I could think about. I would appreciate your comments if you know more reasons.</p>
<ol>
<li>The subscriber&rsquo;s apply worker not consuming the stream fast enough (apply lock contention, slow I/O, heavy CPU load on the subscriber) &mdash; its TCP receive buffer fills up, the TCP window shrinks to zero,&nbsp; the publisher&rsquo;s<br>
			<span id="urvanov-syntax-highlighter-69f2e2a30d6ee441880754" class="urvanov-syntax-highlighter-syntax urvanov-syntax-highlighter-syntax-inline  crayon-theme-classic crayon-theme-classic-inline urvanov-syntax-highlighter-font-monaco" style="font-size: 12px !important;line-height: 15px !important;font-size: 12px !important"><span class="crayon-pre urvanov-syntax-highlighter-code" style="font-size: 12px !important;line-height: 15px !important;font-size: 12px !important"><span class="crayon-e">send</span><span class="crayon-sy">(</span><span class="crayon-sy">)</span></span></span>&nbsp; returns EAGAIN, and the WAL sender spins in the loop.</li>
<li>Saturated network bandwidth between publisher and subscriber. There we have two cases. Traffic originating from Publisher to Subscriber could be slow OR handshake/acknowledgement traffic from Subscriber back to Publisher could be slow. The symptoms may differ.</li>
<li>Large decoded transactions produce bursts of WalSndWriteData calls faster than the network can absorb them. This is generally a temporary problem and the cluster might catchup once the overhead of the large transaction is over.</li>
</ol>
<p>Now the question would be : Now we know all the probable causes, but how to narrow down to the most probable cause ?, so that we can have an action plan.</p>
<p>At Percona, our engineers take time to put all hypotheses for testing, trying to simulate similar conditions and produce observable and reproducible cases. One might argue that we can use low level tracing / OS level tools at this stage to narrow down. Definitely, Yes. That&rsquo;s the most appropriate thing to do. However many of the users may not have low level access and DBaaS offerings prevent it by design. But the good news is that wait &ndash; event patterns can tell us a story in more detail.</p>
<h3><b>Slow Network traffic from Publisher to subscriber</b><a class="anchor-link" id="slow-network-traffic-from-publisher-to-subscriber"></a></h3>
<p>If the network connectivity from Publisher side is slow or suffering with high latency, the send buffer won&rsquo;t get cleared fast enough. Resulting in repeated attempts to send the data.</p>
<p>When we simulated the situation in the lab, we observed the similar Transmission side lag</p>
<p><img decoding="async" loading="lazy" class="alignnone size-full wp-image-45289" src="https://www.percona.com/wp-content/uploads/2026/04/LagInTheLab.png" alt="" width="1549" height="113"></p>
<p>Since this is a network connection problem, automatically the acknowledgment coming from the subscriber side will also be delayed and expected to show lags in all Write, Flush and Replay stages, which is visible in the data collection.</p>
<p>Obviously, our next question is what WALSender is doing ?. The wait events reveal that</p>
<p><img decoding="async" loading="lazy" class="alignnone size-full wp-image-45290" src="https://www.percona.com/wp-content/uploads/2026/04/LagIntheLabWait.png" alt="" width="1658" height="69"></p>
<p>The WAL sender is struggling to send data to Standby. This matches with what the user was seeing in their database.</p>
<p>Meanwhile, at the subscriber side, what we could see is that the apply worker is majorly sitting idle in the main loop: <b>LogicalApplyMain</b></p>
<p><img decoding="async" loading="lazy" class="alignnone size-full wp-image-45291" src="https://www.percona.com/wp-content/uploads/2026/04/WaitingInLogicalApplyMain.png" alt="" width="1615" height="52"></p>
<p>Two other major symptoms to be noted in the cases is 1). much smaller &ldquo;Write lag&rdquo; and compared to &ldquo;Transmission lag&rdquo; and&nbsp; 2.). Both the subscribers are suffering the lag, which is less probable if the problem is on the subscriber side.&nbsp; Even additional clues like data collection running longer when executed from the publisher side about the subscriber instance is also supplementary evidence.</p>
<p>All the above symptoms helps us to conclude with a reasonable level of confidence that the network traffic from the Publisher is the problem.</p>
<h3><b>Overloaded or slow Subscriber node</b><a class="anchor-link" id="overloaded-or-slow-subscriber-node"></a></h3>
<p>The problem could be caused by subscriber not communicating fast enough with Publisher. In such cases the replication lag is expected. I tested that scenario and the following is the observation.<img decoding="async" loading="lazy" class="alignnone size-full wp-image-45292" src="https://www.percona.com/wp-content/uploads/2026/04/SlowSubscriberLag.png" alt="" width="1316" height="118"></p>
<p>The cause of the lag shifts from the &ldquo;Transmission lag&rdquo; to &ldquo;Replica Write Lag&rdquo;, which&nbsp; is the difference between <b>send_lsn</b> and <b>write_lsn</b>.</p>
<p>The WAL Sender / publisher side don&rsquo;t have any problem in sending<img decoding="async" loading="lazy" class="alignnone size-full wp-image-45293" src="https://www.percona.com/wp-content/uploads/2026/04/WALSenderSleeping.png" alt="" width="1997" height="71"></p>
<p>That looks really cool. The major wait event is <strong>WalSenderWaitForWal</strong>. Which means that the WAL sender is just waiting for the next WAL to be flushed and ready, In other words, sleeping until the next commit.</p>
<p>However, the situation on the Subscriber side is different. Unlike in the previous case, the apply worker could be busy with all sorts of work, no more free time to wait in the main loop.</p>
<p><img decoding="async" loading="lazy" class="alignnone size-full wp-image-45294" src="https://www.percona.com/wp-content/uploads/2026/04/SubscriberBusyWaits.png" alt="" width="1927" height="52"></p>
<p>The wait events and their percentage may vary depending on the performance-bottleneck on the subscriber side.</p>
<h3><b>Slow traffic from Subscriber to Publisher</b><a class="anchor-link" id="slow-traffic-from-subscriber-to-publisher"></a></h3>
<p>The impact of the network traffic from the Subscriber side back to Publisher has less effect than that from Publisher side. Because the data flow is from Publisher to Subscriber. The Subscriber needs to send only handshake acknowledgment information back to the publisher, which requires less bandwidth. So an apply worker can be waiting in the main loop (<b>LogicalApplyMain</b>)</p>
<p><img decoding="async" loading="lazy" class="alignnone size-full wp-image-45295" src="https://www.percona.com/wp-content/uploads/2026/04/SlowTrafficFromSubtoPub.png" alt="" width="1999" height="76"></p>
<p>But contrary to expectations, there could be cases of significant CPU usage if there are repeated attempts to reach primary, it may be consuming significant CPU cycles.&nbsp; If we are suspecting network problems from the subscriber side, paying close attention to PostgreSQL logs is important.</p>
<p>There can be timeout captured in PostgreSQL logs at the publisher side</p>
<pre class="urvanov-syntax-highlighter-plain-tag">2026-04-23 17:34:07.078 UTC [36057] postgres@postgres LOG:  terminating walsender process due to replication timeout
2026-04-23 17:34:07.078 UTC [36057] postgres@postgres CONTEXT:  slot "sub", output plugin "pgoutput", in the commit callback, associated LSN DA/70450B8
2026-04-23 17:34:07.078 UTC [36057] postgres@postgres STATEMENT:  START_REPLICATION SLOT "sub" LOGICAL D9/DF13B50 (proto_version '4', streaming 'parallel', origin 'any', publication_names '"pub"')</pre>
<p>Corresponding errors might be appearing at subscriber side also</p>
<pre class="urvanov-syntax-highlighter-plain-tag">2026-04-23 17:36:00.933 UTC [38413] ERROR:  could not receive data from WAL stream: SSL connection has been closed unexpectedly
2026-04-23 17:36:00.940 UTC [38428] LOG:  logical replication apply worker for subscription "sub" has started
2026-04-23 17:36:00.946 UTC [18241] LOG:  background worker "logical replication apply worker" (PID 38413) exited with exit code 1</pre>
<p>All these are indications of poor connection.</p>
<h3>Summary<a class="anchor-link" id="summary"></a></h3>
<p>PostgreSQL Wait events provide lots of visibility into PostgreSQL and underlying infrastructure problems. Reading it with PostgreSQL statistics information (pg_stat_*) and PostgreSQL log&nbsp; could provide answers for a lot of questions as follows easily.</p>
<ol>
<li>Where is the problem ?. Which side of replication is lagging ?</li>
<li>What are WAL Senders and WAL Receivers doing ? Are they busy doing something ? Is there anything pending or sitting idle ?</li>
<li>Are there any hits of underlying infrastructure problems ?</li>
<li>Is the problem correlatable with the wait events ?</li>
</ol>
<p>Collecting and correlating the wait-event data from both sides of the replication, checking the LSN differences,&nbsp; and information from PostgreSQL logs&nbsp; gives us a complete picture.</p>
<p>All it takes is just a couple of minutes! With the right tools and methods in hand. I would like to encourage readers to make use of wait event pattern analysis for easy spotting of performance bottlenecks, if you are not doing it already. It can save you from the treachery of all indepth tracing. Observed Replication lag can be treated as a symptom of something more serious underlying.</p>
<p>This blog is written for those who don&rsquo;t have access to OS level, But if we have access, getting into details is far easier. For example, the send queue (Send-Q) of the Publisher host can be checked like:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">postgres@node0:~$ ss -tnp
State            Recv-Q            Send-Q                         Local Address:Port                       Peer Address:Port             Process
ESTAB            0                 18791538                          172.18.0.2:5432                         172.18.0.3:44974             users:(("postgres",pid=48178,fd=11))</pre>
<p>&nbsp;</p>
<p>The post <a href="https://www.percona.com/blog/troubleshooting-logical-replication-delay-made-easy/">Troubleshooting logical replication delay made easy</a> appeared first on <a href="https://www.percona.com">Percona</a>.</p>

<p>The post <a rel="nofollow" href="https://www.percona.com/blog/troubleshooting-logical-replication-delay-made-easy/">Troubleshooting logical replication delay made easy</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>OIDC error scenarios</title>
      <link>https://percona.community/blog/2026/04/30/oidc-error-scenarios/</link>
      <pubDate>Thu, 30 Apr 2026 00:00:00 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://percona.community/blog/">Percona Community Blog - learn about MySQL, MariaDB, PostgreSQL, and MongoDB</source>
      <description><![CDATA[<p>Last time, in OIDC in PostgreSQL: With Keycloak, we created a working demo setup that was able to successfully authenticate a user using OIDC.</p>
<p>The post <a rel="nofollow" href="https://percona.community/blog/2026/04/30/oidc-error-scenarios/">OIDC error scenarios</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>Last time, in <a href="https://percona.community/blog/2026/01/19/oidc-in-postgresql-with-keycloak/">OIDC in PostgreSQL: With Keycloak</a>, we created a working demo setup that was able to successfully authenticate a user using OIDC.</p>
<p>In this blog post, we follow the same example, but instead of the success story, we explore how OAuth keeps our PostgreSQL servers secure.</p>
<p>We won&rsquo;t focus on complex attack vectors, like the examples in the <a href="https://percona.community/blog/2025/11/17/oidc-in-postgresql-how-it-works-and-staying-secure/">second blog post</a> in the OIDC series.<br>
Instead of social engineering, we&rsquo;ll look at practical errors, misconfigurations and honest mistakes &ndash; understanding error messages and how to fix them.</p>
<h3 id="improved-test-setup">Improved test setup<a class="anchor-link" id="improved-test-setup"></a></h3>
<p>Along with the step by step tutorial, previously we also linked a <a href="https://github.com/Percona-Lab/pg_oidc_validator/tree/main/examples/keycloak" target="_blank" rel="noopener noreferrer">docker/podman compose configuration</a>.<br>
This is still available, and we even improved it for testing the error scenarios.</p>
<p>If you want to update the configuration manually instead, this is what changed: we duplicated everything!</p>
<ul>
<li>Instead of a single testuser, we have two: <code>testuser</code> and <code>testuser2</code>, both using the same <code>asdfasdf</code> password</li>
<li>Instead of one client, we have two: <code>pgtest</code> and <code>pgtest2</code></li>
<li>Instead of one scope, we have two: <code>pgscope</code>, <code>pgscope2</code></li>
<li>Instead of one realm, we have two &ndash; containing exactly the same setup: <code>pgrealm</code> and <code>wrongrealm</code></li>
</ul>
<p>A role named <code>pgrole</code> is also defined.<br>
The <code>pgtest2</code> client and <code>pgscope2</code> scope both require the <code>pgrole</code> role.<br>
Only <code>testuser2</code> is assigned this role; <code>testuser</code> does not have it.</p>
<p>The following table summarizes the access matrix:</p>
<table>
<thead>
<tr>
<th></th>
<th>pgtest</th>
<th>pgtest2</th>
<th>pgscope</th>
<th>pgscope2</th>
</tr>
</thead>
<tbody>
<tr>
<td>testuser</td>
<td>OK</td>
<td>denied</td>
<td>OK</td>
<td>denied</td>
</tr>
<tr>
<td>testuser2</td>
<td>OK</td>
<td>OK</td>
<td>OK</td>
<td>OK</td>
</tr>
</tbody>
</table>
<h3 id="success-despite-a-fatal-error">Success despite a FATAL error?<a class="anchor-link" id="success-despite-a-fatal-error"></a></h3>
<p>However, before we start using all these additional items, let&rsquo;s go back to the end of the Keycloak story, where we succeeded in logging in.<br>
Or did we?<br>
While <code>psql</code> logged us in, if we checked the server error log, we could see the following there:</p>
<div class="code-block">
<div class="code-block__header"><button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-0">
<div class="highlight">
<pre class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">FATAL: OAuth bearer authentication failed for user "testuser"</span></span></code></pre>
</div>
</div>
</div>
<p>But if we are observant enough, this message is logged before we even go to the device authentication website of Keycloak, and enter the authentication code.<br>
This isn&rsquo;t a real error, it&rsquo;s just a side effect of how OAuth is implemented internally, and will most likely be fixed in PostgreSQL 19, the FATAL message will no longer show up.</p>
<p>As for PostgreSQL 18, unfortunately, we have to live with this.<br>
This also means that we can&rsquo;t rely on simply looking for OAuth authentication errors in the server log, because all OAuth authentication failures will result in exactly the same message, no matter if they are logged because of this harmless situation or because of a real authentication issue.</p>
<p>A workaround is to rely on the validators instead: since the server is unaware of the exact error situation anyway &ndash; it delegates validation to the validator &ndash; these plugins will print out much more detailed <em>log messages</em>.<br>
We&rsquo;ll see some examples later with pg_oidc_validator, as we explore the error scenarios.</p>
<p>However, keep in mind that the sentence above says <em>log messages</em>, and not <em>errors</em> or <em>fatal errors</em>.<br>
Validators are not allowed to print out ERROR and FATAL messages for authentication failures, so users have to look for WARNING or LOG level messages for the details.<br>
In practice, PostgreSQL will still print the same generic FATAL error message about OAuth bearer authentication failing &ndash; but it will appear after the validator-specific WARNING or LOG messages that contain the actual diagnostic information.</p>
<h3 id="why-does-it-happen">Why does it happen?<a class="anchor-link" id="why-does-it-happen"></a></h3>
<p>Earlier we already established that PostgreSQL validates that the client and the server use the same issuer, but didn&rsquo;t go into more detail than this.</p>
<p>Usually when a service validates user input, it does so on the server.<br>
The main reason for this is that developers can trust the backend, controlled by administrators, while they can&rsquo;t trust the frontend, potentially used by malicious users.</p>
<p>But are we validating user input in this case?<br>
Why does the user even have to specify the issuer, since the server already knows it, it&rsquo;s in the HBA configuration?</p>
<p>Because this check isn&rsquo;t the server validating the user, it&rsquo;s the opposite:<br>
the user validating the server.</p>
<ol>
<li>The client sends an empty connection request to the server.</li>
<li>The server confirms that we are using OAuth, and sends back its issuer URL.</li>
<li>The client checks whether the issuer it is planning to use &ndash; or has already used, if it already has a valid token &ndash; matches the one sent by the server.
<ul>
<li>If it doesn&rsquo;t match, it aborts the login attempt and prints an error.</li>
<li>If it does match, it continues with a real authentication attempt.</li>
</ul>
</li>
</ol>
<pre class="mermaid">
sequenceDiagram
participant C as psql (Client)
participant S as PostgreSQL Server
participant K as Keycloak
C-&gt;&gt;S: Connection request (no token)
S--&gt;&gt;S: No token, auth fails
Note right of S: FATAL logged here (harmless side effect)
S-&gt;&gt;C: OAuth challenge + issuer URL
C--&gt;&gt;C: Compare issuer URL with oauth_issuer
alt Issuer mismatch
C--&gt;&gt;C: Abort with error
else Issuer matches
C-&gt;&gt;K: Device authorization flow
K-&gt;&gt;C: Access token
C-&gt;&gt;S: Connection request (with token)
S-&gt;&gt;S: Validator checks token
S-&gt;&gt;C: Authentication success
end
</pre>
<p>The FATAL error in the server log is a side effect of the first empty authentication attempt, that wasn&rsquo;t fixed in time before the PG18 release.</p>
<h3 id="why-do-we-need-this-check">Why do we need this check?<a class="anchor-link" id="why-do-we-need-this-check"></a></h3>
<p>With the improved configuration, we can test what happens when we specify the wrong issuer:</p>
<div class="code-block">
<div class="code-block__header"><button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-2">
<div class="highlight">
<pre class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">bin/psql -h 127.0.0.1 'dbname=postgres oauth_issuer=https://keycloak:8443/realms/wrongrealm oauth_client_id=pgtest'
</span></span><span class="line"><span class="cl">psql: error: connection to server at "127.0.0.1", port 5432 failed: server's discovery document at https://keycloak:8443/realms/pgrealm/.well-known/openid-configuration (issuer "https://keycloak:8443/realms/pgrealm") is incompatible with oauth_issuer (https://keycloak:8443/realms/wrongrealm)</span></span></code></pre>
</div>
</div>
</div>
<p>Notice that compared to the correct command, which had the pgrealm, we are using the other Keycloak realm.<br>
And if we check the server log, we can see that there are no additional log messages there &ndash; we see a single OAuth FATAL error, which is not a real error, just the side effect we are investigating.<br>
This error is entirely on the client side.</p>
<p>And that brings us back to the question:<br>
why do we need this?</p>
<p>On one hand, it helps us prevent honest mistakes early.<br>
In our example, wrongrealm and pgrealm are exactly the same &ndash; they have users with the same name, scopes with the same names, clients with the same names.<br>
If there&rsquo;s a misconfiguration, and the server and the client use different realms in a similar setup, everything would seem to work &ndash; the user trying to log in would be able to log in, get a token, psql would send it to the server&hellip;<br>
and then on the server the validator would reject it &ndash; assuming that it is a good validator, like pg_oidc_validator.<br>
No harm done &ndash; other than disclosing a token to the server that shouldn&rsquo;t have been sent there &ndash;, but figuring out what the problem is could take a while.</p>
<p>On the other hand: what if we aren&rsquo;t dealing with a malicious user, but a malicious server?</p>
<p>In the previous attack vectors we showcased, the attacker was always a third party:<br>
somebody who wanted to steal access to the database server.</p>
<p>But we don&rsquo;t necessarily need a different unknown adversary, it could be the server we are using:<br>
do we absolutely know and trust its administrators?<br>
Sometimes yes, sometimes no.</p>
<p>Those administrators might be aware that we are also using OAuth for something else, and might plot to gain access to it.<br>
So instead of sending us the issuer we expect, the server sends us something else &ndash; for example a spoofed site, tricking us to complete login into a different service.</p>
<p>Remember the earlier situation where the Fake Photo Gallery Website used Client ID spoofing to gain access to the PostgreSQL Database?<br>
This situation is basically the same &ndash; the only difference is that this time PostgreSQL Database is trying to gain access to Photo Gallery.</p>
<pre class="mermaid">
sequenceDiagram
participant U as User (psql)
participant M as Malicious PostgreSQL Server
participant SSO as Other service
U-&gt;&gt;M: Connection request
M-&gt;&gt;U: OAuth challenge + spoofed issuer URL (instead of expected issuer)
Note over U: Without issuer check, user proceeds
U-&gt;&gt;SSO: Authenticates, thinking it is for PostgreSQL
SSO-&gt;&gt;U: Access token (valid for a different service)
U-&gt;&gt;M: Sends token to server
Note over M: Malicious server now holds a token valid for the other service
</pre>
<p>The client-side issuer check prevents this: psql compares the issuer URL from the server against the <code>oauth_issuer</code> it was configured with, and aborts if they don&rsquo;t match.</p>
<p>While requiring the client to specify the issuer may seem redundant, it&rsquo;s an important safeguard that prevents tokens from being disclosed to malicious servers.</p>
<h3 id="can-we-verify-the-validator">Can we verify the validator?<a class="anchor-link" id="can-we-verify-the-validator"></a></h3>
<p>If we specify an incorrect issuer, the client rejects it before completing the OAuth flow &ndash; that&rsquo;s great, but this means the validator isn&rsquo;t part of the picture.<br>
Can we even test that a validator handles this situation correctly, to verify that it properly rejects an attempt with an incorrect issuer?<br>
Security-aware users might want to double check that somebody using a modified psql is also properly rejected.</p>
<p>This is possible: in our next blog post, we&rsquo;ll see how to implement custom clients outside psql, possibly using other OAuth flows.<br>
In that scenario, we&rsquo;ll be able to send custom tokens to the server, which has many uses &ndash; one of which is internal testing of OAuth validators.</p>
<p>Rest assured, pg_oidc_validator handles this correctly &ndash; and we&rsquo;ll show you how to verify it yourself in the next post.<br>
If you are using a different validator, stay tuned to see how you can verify it!</p>
<p>With pg_oidc_validator, you will see something like this in the server log:</p>
<div class="code-block">
<div class="code-block__header"><button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-4">
<div class="highlight">
<pre class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">WARNING: OAuth validation failed with exception: claim value does not match expected value
</span></span><span class="line"><span class="cl">FATAL: OAuth bearer authentication failed for user "testuser"
</span></span><span class="line"><span class="cl">DETAIL: Connection matched file "/pg_hba.conf" line 119: "host all all 127.0.0.1/32 oauth issuer=https://keycloak:8443/realms/pgrealm,scope="pgscope email",map=kcmap"</span></span></code></pre>
</div>
</div>
</div>
<p>Here &ldquo;claim value does not match expected value&rdquo; means that a field (claim) in the JWT doesn&rsquo;t match our expectation.<br>
While this might seem generic, currently pg_oidc_validator only validates exactly one field in this way: the issuer.</p>
<p>On the client side, you can see the following generic error message:</p>
<div class="code-block">
<div class="code-block__header"><button class="code-block__copy" type="button" data-copy-target="codeblock-5" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-5">
<div class="highlight">
<pre class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Connection error: connection to server at "127.0.0.1", port 5432 failed: retrying connection with new bearer token
</span></span><span class="line"><span class="cl">connection to server at "127.0.0.1", port 5432 failed: FATAL: OAuth bearer authentication failed for user "testuser"</span></span></code></pre>
</div>
</div>
</div>
<p>Which is generally true for most OAuth errors &ndash; validators are expected not to provide detailed information about why they reject a connection back to the client, to limit the information available to potential attackers.</p>
<h3 id="signature-failure">Signature failure<a class="anchor-link" id="signature-failure"></a></h3>
<p>For some it might be surprising that we are getting an error about the issuer, and not about the token.<br>
Why is that?</p>
<p>The reason we use JWTs for access tokens is because they are cryptographically signed tokens.<br>
While they contain the payload in clear text, the token ends with a signature, a proof that it was generated by the issuer we trust.</p>
<p>This means that if the token was generated by a different issuer, it is signed by a different key.</p>
<p>However, the order of operations inside the validator is different:<br>
first we validate the fields in the cleartext data we have strong expectations about &ndash; in this case the issuer.<br>
Then, after that&rsquo;s valid, we also verify that the signature matches the public key of the issuer.</p>
<p>Since in the above situation the issuer is different, we never get to the point of signature validation.</p>
<p>To do that, somebody has to tamper with the token.<br>
For example, an attacker realizes that we require a specific scope, and since JWTs contain everything in clear text, decides to edit the <code>scp</code> claim and insert <code>pgscope</code> into it.<br>
In that situation, the issuer matches, the validator verifies the signature, and we end up with a different error:</p>
<div class="code-block">
<div class="code-block__header"><button class="code-block__copy" type="button" data-copy-target="codeblock-6" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-6">
<div class="highlight">
<pre class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">WARNING: OAuth validation failed with exception: failed to verify signature: VerifyFinal failed
</span></span><span class="line"><span class="cl">FATAL: OAuth bearer authentication failed for user "testuser"
</span></span><span class="line"><span class="cl">DETAIL: Connection matched file "/pg_hba.conf" line 119: "host all all 127.0.0.1/32 oauth issuer=https://keycloak:8443/realms/pgrealm,scope="pgscope email",map=kcmap"</span></span></code></pre>
</div>
</div>
</div>
<p>The client side error message didn&rsquo;t change with this &ndash; this is clearly an attack attempt, we do not have to provide nice error messages for malicious users.</p>
<h3 id="what-about-expired-tokens">What about expired tokens?<a class="anchor-link" id="what-about-expired-tokens"></a></h3>
<p>Another interesting scenario you might wonder about is token lifetime:<br>
in OAuth, tokens have a limited period in which they are valid.</p>
<p>PostgreSQL currently has no facilities to enforce token lifetime when a connection is active &ndash; once somebody is logged in, they stay logged in until they disconnect for some reason &ndash;, but validators are expected to validate that tokens are still valid at least during authentication.</p>
<p>Similarly to the previous situation, testing this without a custom client isn&rsquo;t possible, as psql always asks for a new token during the connection attempt, there is no way to send an earlier token with it.</p>
<p>As in the previous example, this scenario is rejected by pg_oidc_validator, which logs the following message on the server:</p>
<div class="code-block">
<div class="code-block__header"><button class="code-block__copy" type="button" data-copy-target="codeblock-7" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-7">
<div class="highlight">
<pre class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">WARNING: OAuth validation failed with exception: token expired
</span></span><span class="line"><span class="cl">FATAL: OAuth bearer authentication failed for user "testuser"
</span></span><span class="line"><span class="cl">DETAIL: Connection matched file "/pg_hba.conf" line 119: "host all all 127.0.0.1/32 oauth issuer=https://keycloak:8443/realms/pgrealm,scope="pgscope email",map=kcmap"</span></span></code></pre>
</div>
</div>
</div>
<p>On the client side, you can only see the same generic error message as before.</p>
<p>While this doesn&rsquo;t seem too user friendly, keep in mind that both of these errors can only happen with faulty clients.<br>
Clients can, and should verify both the issuer and the expiration time before connecting to the server, and they should be able to provide nice error messages to the users based on that.</p>
<h3 id="scope-mismatch">Scope mismatch<a class="anchor-link" id="scope-mismatch"></a></h3>
<p>After the previous two situations, which are untestable with <code>psql</code>, let&rsquo;s move to the realm of errors which don&rsquo;t require custom code.</p>
<p>In the first and second blog posts we tried to emphasize how important scopes are in OAuth, how they can help prevent accidents.<br>
Obviously, validators have to make sure that all the scopes the server asked for are present in the received token.<br>
Having more scopes isn&rsquo;t an issue &ndash; sometimes clients use the same token for multiple services &ndash;, but missing a required scope should be an error.</p>
<p>To verify what happens in this situation, we can simply modify the pg_hba line to include a scope that doesn&rsquo;t exist on the server, for example adding <code>fooscope</code>:</p>
<div class="code-block">
<div class="code-block__header"><button class="code-block__copy" type="button" data-copy-target="codeblock-8" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-8">
<div class="highlight">
<pre class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">host all all 127.0.0.1/32 oauth issuer=https://keycloak:8443/realms/pgrealm,scope="pgscope email fooscope",map=kcmap</span></span></code></pre>
</div>
</div>
</div>
<p>And then we can connect with psql as before:</p>
<div class="code-block">
<div class="code-block__header"><button class="code-block__copy" type="button" data-copy-target="codeblock-9" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-9">
<div class="highlight">
<pre class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">bin/psql -h 127.0.0.1 'dbname=postgres oauth_issuer=https://keycloak:8443/realms/pgrealm oauth_client_id=pgtest'</span></span></code></pre>
</div>
</div>
</div>
<p>Which should result in the following detailed error message in the server log:</p>
<div class="code-block">
<div class="code-block__header"><button class="code-block__copy" type="button" data-copy-target="codeblock-10" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-10">
<div class="highlight">
<pre class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">LOG: Authorization failed because of scope mismatch. Required scopes: email, fooscope, pgscope. Received scopes: email, pgscope, profile
</span></span><span class="line"><span class="cl">LOG: OAuth bearer authentication failed for user "testuser"
</span></span><span class="line"><span class="cl">DETAIL: Validator failed to authorize the provided token.
</span></span><span class="line"><span class="cl">FATAL: OAuth bearer authentication failed for user "testuser"
</span></span><span class="line"><span class="cl">DETAIL: Connection matched file "/pg_hba.conf" line 119: "host all all 127.0.0.1/32 oauth issuer=https://keycloak:8443/realms/pgrealm,scope="pgscope email fooscope",map=kcmap"</span></span></code></pre>
</div>
</div>
</div>
<p>Similarly to the previous scenarios, this is completely validator specific, we can only showcase our validator.</p>
<p>This scenario also depends on the OAuth flow used and the identity provider.<br>
<strong>Note:</strong> Keycloak, for example, permits unknown scopes for the device flow &ndash; it simply ignores them and returns the scopes it can.<br>
However, it doesn&rsquo;t do that for other flows &ndash; the Token Endpoint rejects unknown scopes with an error and doesn&rsquo;t provide an access token.</p>
<p>On the client side, the error is the same as before &ndash; no details about what&rsquo;s missing.<br>
Which is fine in this situation, as this is clearly a configuration error, something the administrators have to figure out and fix.</p>
<p>Now let&rsquo;s see the error slightly differently.</p>
<p>The above example worked with the unmodified keycloak setup, described in the previous blog, but we have an improved test setup for this one.<br>
Instead of using a non existent foo scope, let&rsquo;s change our requirement to <code>pgscope2</code>, which requires <code>pgrole</code>:</p>
<div class="code-block">
<div class="code-block__header"><button class="code-block__copy" type="button" data-copy-target="codeblock-11" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-11">
<div class="highlight">
<pre class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">host all all 127.0.0.1/32 oauth issuer=https://keycloak:8443/realms/pgrealm,scope="pgscope2 email",map=kcmap</span></span></code></pre>
</div>
</div>
</div>
<p>And similarly add <code>testuser2</code> to pg_ident, so both can log in:</p>
<div class="code-block">
<div class="code-block__header"><button class="code-block__copy" type="button" data-copy-target="codeblock-12" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-12">
<div class="highlight">
<pre class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl"># MAPNAME SYSTEM-USERNAME DATABASE-USERNAME
</span></span><span class="line"><span class="cl">kcmap testuser@example.com testuser
</span></span><span class="line"><span class="cl">kcmap testuser2@example.com testuser2</span></span></code></pre>
</div>
</div>
</div>
<p>In this new setup, we transformed the configuration problem into a permission issue where testuser2 can log in and testuser can not.</p>
<p>The error message on the client side is unchanged, it still doesn&rsquo;t say &ldquo;permission denied&rdquo; or &ldquo;scope mismatch&rdquo;, or anything like that.<br>
This is debatable, but it is still mainly a task for administrators, and not the user:<br>
somebody will have to investigate the permission setup on keycloak, and fix it, if testuser also needs access to the server.</p>
<h3 id="unknown-user">Unknown user<a class="anchor-link" id="unknown-user"></a></h3>
<p>Another common error source is a problem with the user mapping.<br>
In our example we are using a pg_ident file with an email, but it would be similar with other configurations.</p>
<p>Regardless of the setup, there are many reasons why we can&rsquo;t properly look up a username:</p>
<ul>
<li>using an incorrect field for <code>authn_field</code></li>
<li>missing an entry from <code>pg_ident</code></li>
<li>having a typo in the name either in <code>pg_ident</code> or in keycloak</li>
<li>and so on</li>
</ul>
<p>In all situations, the error message for this case won&rsquo;t be generated in the validator, but in the PostgreSQL user mapping code instead.<br>
For example, if you previously added <code>testuser2</code> to the ident file, comment it out and try to log in with it again:</p>
<div class="code-block">
<div class="code-block__header"><button class="code-block__copy" type="button" data-copy-target="codeblock-13" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-13">
<div class="highlight">
<pre class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">LOG: no match in usermap "kcmap" for user "testuser" authenticated as "testuser2@example.com"
</span></span><span class="line"><span class="cl">FATAL: OAuth bearer authentication failed for user "testuser"
</span></span><span class="line"><span class="cl">DETAIL: Connection matched file "/pg_hba.conf" line 119: "host all all 127.0.0.1/32 oauth issuer=https://keycloak:8443/realms/pgrealm,scope="pgscope email",map=kcmap"</span></span></code></pre>
</div>
</div>
</div>
<p>In an alternative configuration &ndash; which is not part of the sample keycloak configuration &ndash; it is possible to create a custom claim &ldquo;postgres_username&rdquo; on keycloak, and skip the map file completely.<br>
In this situation, a mismatched username would result in a slightly different error message:</p>
<div class="code-block">
<div class="code-block__header"><button class="code-block__copy" type="button" data-copy-target="codeblock-14" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-14">
<div class="highlight">
<pre class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">LOG: provided user name (testuser) and authenticated user name (testuser2) do not match
</span></span><span class="line"><span class="cl">FATAL: OAuth bearer authentication failed for user "testuser"
</span></span><span class="line"><span class="cl">DETAIL: Connection matched file "/pg_hba.conf" line 119: "host all all 127.0.0.1/32 oauth issuer=https://keycloak:8443/realms/pgrealm,scope="pgscope email""</span></span></code></pre>
</div>
</div>
</div>
<h3 id="connection-problems">Connection problems<a class="anchor-link" id="connection-problems"></a></h3>
<p>While it usually isn&rsquo;t a configuration or permission problem, it is possible that we have a network issue:<br>
either a localized routing error, where the client can connect to the identity provider but the server can&rsquo;t, or a situation where the identity provider / network crashed between obtaining the access token and verifying it on the server.</p>
<p>The client executable has an access token and sends it to the server, which then has to validate it without being able to communicate with the identity provider.<br>
This is another situation which is difficult to validate with <code>psql</code>, but it is relatively easy with a custom client.</p>
<p>Our OIDC validator has to connect to the identity provider for two reasons:</p>
<ul>
<li>One, to retrieve the discovery document which contains the URL of the JWKS endpoint &ndash; which stores the public keys of the issuer</li>
<li>Two, to retrieve the public keys using that JWKS endpoint</li>
</ul>
<p>The validator also follows HTTP Cache headers:<br>
for example, if the server allows caching the keys for 4 days, the validator only retrieves them for the first attempt, and then keeps using them for that time.<br>
After it passes, it connects to the server one more time, and if it again receives a 4 day window, it will keep using the keys for 4 more days.<br>
This means that with a proper provider setup, the validator might not even notice a short service loss.</p>
<p>Fortunately for our testing, but not so fortunately for production use, keycloak doesn&rsquo;t support JWKS caching at all.</p>
<p>An inaccessible OIDC server will result in logs similar to:</p>
<div class="code-block">
<div class="code-block__header"><button class="code-block__copy" type="button" data-copy-target="codeblock-15" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-15">
<div class="highlight">
<pre class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">WARNING: OAuth validation failed with exception: HTTP request failed: Could not connect to server
</span></span><span class="line"><span class="cl">FATAL: OAuth bearer authentication failed for user "testuser"
</span></span><span class="line"><span class="cl">DETAIL: Connection matched file "/pg_hba.conf" line 119: "host all all 127.0.0.1/32 oauth issuer=https://keycloak:8443/realms/pgrealm,scope="pgscope email",map=kcmap"</span></span></code></pre>
</div>
</div>
</div>
<p>Where the exact error message depends on the situation &ndash; a timeout, internal server error, etc, all would result in slightly different error messages, while a timeout would also slow down the response time of the authentication attempt.</p>
<h3 id="lets-run-without-errors">Let&rsquo;s run without errors!<a class="anchor-link" id="lets-run-without-errors"></a></h3>
<p>We hope these examples will be useful for everybody. To avoid errors, to diagnose problems, and to simply understand the security model and guarantees given by OAuth and validators.</p>
<p>While this is not an all-inclusive list, as we can&rsquo;t possibly cover every error scenario in a setup involving several components, it covers the most common scenarios, and should address all possible security problems.</p>
<p>In our next blog post, we&rsquo;ll focus on a practical, minimal development example:<br>
while currently only the provided command line tools support OAuth, <code>libpq</code> already has the infrastructure in it to implement custom OAuth logic, allowing users to integrate it into their applications &ndash; we&rsquo;ll provide examples how it is doable.</p>

<p>The post <a rel="nofollow" href="https://percona.community/blog/2026/04/30/oidc-error-scenarios/">OIDC error scenarios</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>XtraBackup incremental prepare phase is 2x-3x faster!</title>
      <link>https://www.percona.com/blog/xtrabackup-incremental-prepare-phase-is-2x-3x-faster/</link>
      <pubDate>Wed, 29 Apr 2026 18:52:44 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://www.percona.com/blog/">Blog - Percona</source>
      <description><![CDATA[<p>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. … Continued<br />
The post XtraBackup incremental prepare phase is 2x-3x faster! appeared first on Percona.</p>
<p>The post <a rel="nofollow" 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 rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<h2><b>TL;DR</b><a class="anchor-link" id="tldr"></a></h2>
<p><b>Percona XtraBackup</b> is a 100% open-source backup solution for Percona Server for MySQL and MySQL&reg;. 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 &ldquo;prepare&rdquo; 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 style="color: #000000"><b>8.0.35-33</b></span> and <span style="color: #000000"><b>8.4.0-3</b></span> and later, we&rsquo;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><a class="anchor-link" id="the-incremental-backup-workflow"></a></h2>
<p>Before we dive into the performance gains, it&rsquo;s important to understand how Incremental backups work.</p>
<h3><b>1. Creating the Backups</b><a class="anchor-link" id="1-creating-the-backups"></a></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&rsquo;s review an example.</p>
<ul>
<li><b>Take Full Backup:</b> Your starting point is Point A. This backup is an entire copy of your data.</li>
<li><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><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><a class="anchor-link" id="2-preparing-the-backups"></a></h3>
<p>To restore the data to the latest point, you must merge these changes back into the full backup. The &ldquo;prepare&rdquo; phase works differently here:</p>
<ul>
<li><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><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><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><a class="anchor-link" id="the-improvement-parallel-incremental-delta-apply"></a></h2>
<p>We have improved the <b>Incremental Delta Apply</b> phase. These are &ldquo;<b>Prepare inc1&rdquo;</b> and &ldquo;<b>Prepare inc2</b>&rdquo; 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><a class="anchor-link" id="benchmarks"></a></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 decoding="async" loading="lazy" 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"></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 &ldquo;golden value&rdquo; 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><a class="anchor-link" id="disk-utilization-with-xtrabackup-prepare-using-parallel1-vs-parallel64"></a></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><a class="anchor-link" id="with-parallel1"></a></h3>
<p><img decoding="async" loading="lazy" 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"></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><a class="anchor-link" id="with-parallel64"></a></h3>
<p><img decoding="async" loading="lazy" 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"></p>
<p>&nbsp;</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><a class="anchor-link" id="results-from-the-bug-reporter"></a></h2>
<p>We saw some amazing results shared by the reporter on <a href="https://perconadev.atlassian.net/browse/PXB-3427">PXB-3427</a>.&nbsp; The time required for XtraBackup prepare command (<code>--prepare --apply-log-only</code>)&nbsp; to complete, reduced from <b>237 minutes to just 6 minutes</b>. That&rsquo;s an incredible <b>40X speed-up</b>!</p>
<p>Here are the details from their setup:</p>
<ul>
<li><b>Full backup:</b> 235,188 *.ibd files</li>
<li><b>Incremental backup:</b> 236,214 *.ibd.delta files</li>
<li><b>Average </b><b>.delta</b><b> size:</b> 53,041 bytes (~53KB)</li>
<li><b>Threads used:</b> 48 (&ndash;parallel=48)</li>
<li><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>

<p>The post <a rel="nofollow" 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 rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Orchestrator’s Next Chapter: What It Means for Percona Customers</title>
      <link>https://www.percona.com/blog/orchestrators-next-chapter-what-it-means-for-percona-customers/</link>
      <pubDate>Wed, 29 Apr 2026 17:55:10 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://www.percona.com/blog/">Blog - Percona</source>
      <description><![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: Announcing the future of Orchestrator. We want to briefly share Percona’s position on the news. We welcome this Orchestrator became the de … Continued<br />
The post Orchestrator’s Next Chapter: What It Means for Percona Customers appeared first on Percona.</p>
<p>The post <a rel="nofollow" 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 rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></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&rsquo;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&rsquo;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&rsquo;s role</h4>
<p>The ProxySQL announcement kindly credited Percona alongside GitHub for &ldquo;stewardship over the years.&rdquo; 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&rsquo;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&rsquo;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&rsquo;re a Percona customer, reach out to your account team with any questions about your Orchestrator deployment. If you&rsquo;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>&nbsp;</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&rsquo;s Next Chapter: What It Means for Percona Customers</a> appeared first on <a href="https://www.percona.com">Percona</a>.</p>

<p>The post <a rel="nofollow" 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 rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Adding a New Data Type to MariaDB with Type_handler – Part 0</title>
      <link>https://mariadb.org/adding-a-new-data-type-to-mariadb-with-type_handler-part-0/</link>
      <pubDate>Wed, 29 Apr 2026 09:37:01 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.org/">MariaDB.org</source>
      <description><![CDATA[<p>Welcome to this new series about extending MariaDB. This series covers the addition of a new data type using the Type_handler.<br />
The goal of the entire series is to create a new plugin data type MONEY to store and display amounts with currency. …<br />
Continue reading \"Adding a New Data Type to MariaDB with Type_handler – Part 0\"<br />
The post Adding a New Data Type to MariaDB with Type_handler – Part 0 appeared first on MariaDB.org.</p>
<p>The post <a rel="nofollow" href="https://mariadb.org/adding-a-new-data-type-to-mariadb-with-type_handler-part-0/">Adding a New Data Type to MariaDB with Type_handler – Part 0</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>Welcome to this new series about extending MariaDB. This series covers the addition of a new data type using the <a href="https://www.linkedin.com/pulse/mariadbs-pluggable-data-type-framework-deep-dive-drrtuy-drrtuy-p6yke/">Type_handler</a>.<br>
The goal of the entire series is to create a new plugin data type MONEY to store and display amounts with currency. &hellip; </p>
<p class="link-more"><a href="https://mariadb.org/adding-a-new-data-type-to-mariadb-with-type_handler-part-0/" class="more-link">Continue reading<span class="screen-reader-text"> &ldquo;Adding a New Data Type to MariaDB with Type_handler &ndash; Part 0&rdquo;</span></a></p>
<p>The post <a rel="nofollow" href="https://mariadb.org/adding-a-new-data-type-to-mariadb-with-type_handler-part-0/">Adding a New Data Type to MariaDB with Type_handler &ndash; Part 0</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>

<p>The post <a rel="nofollow" href="https://mariadb.org/adding-a-new-data-type-to-mariadb-with-type_handler-part-0/">Adding a New Data Type to MariaDB with Type_handler – Part 0</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>pgBackRest is archived, what now?</title>
      <link>https://percona.community/blog/2026/04/28/pgbackrest-is-archived-what-now/</link>
      <pubDate>Tue, 28 Apr 2026 11:00:00 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://percona.community/blog/">Percona Community Blog - learn about MySQL, MariaDB, PostgreSQL, and MongoDB</source>
      <description><![CDATA[<p>pgBackRest is an open source backup and restore tool for PostgreSQL. It’s fair to say it’s one of the most popular options, widely used across the PostgreSQL ecosystem.</p>
<p>The post <a rel="nofollow" href="https://percona.community/blog/2026/04/28/pgbackrest-is-archived-what-now/">pgBackRest is archived, what now?</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p><a href="https://github.com/pgbackrest/pgbackrest" target="_blank" rel="noopener noreferrer">pgBackRest</a> is an open source backup and restore tool for PostgreSQL. It&rsquo;s fair to say it&rsquo;s one of the most popular options, widely used across the PostgreSQL ecosystem.</p>
<p>On 27 April 2026, pgBackRest maintainer David Steele announced on <a href="https://www.linkedin.com/posts/davidsteele_after-a-lot-of-thought-i-have-decided-to-share-7454442611911655424-mVMS?utm_source=share&amp;utm_medium=member_desktop&amp;rcm=ACoAAAD3qpgBKSXefFXDYJlyIbIdar9mZh-NYBw" target="_blank" rel="noopener noreferrer">LinkedIn</a> and in the <a href="https://github.com/pgbackrest/pgbackrest" target="_blank" rel="noopener noreferrer">GitHub repository</a> that the project is becoming <del>unmaintained</del> archived, starting with:</p>
<blockquote>
<p>TL;DR: pgBackRest is no longer being maintained. If you fork pgBackRest, please select a new name for your project.</p>
</blockquote>
<div style="width:70%;margin: auto">
<p><figure><img decoding="async" src="https://percona.community/blog/2026/04/Jan-david-li.png" alt="&nbsp;"></figure>
</p>
</div>
<p>If you&rsquo;re reading this, you&rsquo;re likely either affected or at least concerned. In this short write up I will do my best to calm your nerves, present short term as well as more long term ideas and options.</p>
<h2 id="where-are-we-now---the-status-quo">Where are we now &ndash; the status quo<a class="anchor-link" id="where-are-we-now-the-status-quo"></a></h2>
<p>pgBackRest is a critical part of the PostgreSQL ecosystem, and nobody seriously expects it to simply disappear. What happens next is now up to the community.<br>
One possible outcome is the emergence of multiple forks of pgBackRest. That raises the risk of fragmentation or, put bluntly, <del>Clone</del> Fork Wars.</p>
<div style="width:70%;margin: auto">
<p><figure>
<img decoding="async" src="https://percona.community/blog/2026/04/Jan-forks.png" alt="&nbsp;"></figure>
</p>
</div>
<p>That said, there has already been a significant amount of discussion across the community, and one thing is clear:</p>
<p>The PostgreSQL community acknowledges the problem and wants change.</p>
<p>The challenge now is twofold:</p>
<ul>
<li>What can we do immediately to stabilize the situation?</li>
<li>What direction should we take long term, without overcomplicating the short-term response?</li>
</ul>
<h2 id="what-is-percona-planning">What is Percona planning<a class="anchor-link" id="what-is-percona-planning"></a></h2>
<p><a href="https://docs.percona.com/postgresql/14/solutions/backup-recovery.html#pgbackrest" target="_blank" rel="noopener noreferrer">Percona includes pgBackRest</a> in the <a href="https://docs.percona.com/postgresql/14/index.html" target="_blank" rel="noopener noreferrer">Percona Distribution for PostgreSQL</a> as the recommended backup and restore solution. From our perspective, it remains the most mature, enterprise-ready and reliable option available. While alternatives like WAL-G or Barman are well regarded, our recommendation remains unchanged.</p>
<p>To emphasize the message:</p>
<blockquote>
<p>the current situation does <u>not</u> impact our recommendation.</p>
</blockquote>
<p>Percona will continue supporting pgBackRest. What that support looks like in terms of maintainership and collaboration with other organizations is still being actively discussed and will take time to solidify.</p>
<p>The immediate priority is to avoid fragmentation. We want to ensure we don&rsquo;t end up with multiple independent forks maintained in isolation.</p>
<p>If you are a Percona customer, you remain fully supported. Please continue reporting issues through standard support channels. For our community users, we encourage you to use the <a href="https://forums.percona.com/" target="_blank" rel="noopener noreferrer">Percona Community Forums</a>, we will do our best to help there.</p>
<h2 id="the-power-of-open-source-community">The power of open source community<a class="anchor-link" id="the-power-of-open-source-community"></a></h2>
<p>In an era where we often hear about companies reducing teams due to AI-driven cost optimization, it&rsquo;s easy to forget that software is still built and maintained by people. This is especially true in open source.</p>
<p>Two observations are worth calling out:</p>
<ol>
<li>People need sustainable funding, work cannot be assumed to be purely voluntary.</li>
<li>A healthy open source project should not depend on a single company or individual.</li>
</ol>
<p>The current situation is, to some extent, a result of the opposite model. pgBackRest development was largely driven by a single company and later single maintainer, <a href="https://github.com/dwsteele" target="_blank" rel="noopener noreferrer">David Steele</a>, with sponsorship from Crunchy Data. While others have contributed (e.g.i <a href="https://github.com/sfrost" target="_blank" rel="noopener noreferrer">Stephen Frost</a> and Stefan Fercot &ndash; <a href="https://github.com/pgstef" target="_blank" rel="noopener noreferrer">pgstef</a>), and there was a wider team maintaining the project in the past, recently the project effectively relied on one primary maintainer.</p>
<p>I think it&rsquo;s fair to say we&rsquo;ve seen a fair share <a href="https://xkcd.com/2347/" target="_blank" rel="noopener noreferrer">xkcd #2347</a> posted all over the internet over the course of last 24h. So here&rsquo;s one more:</p>
<div style="width:50%;margin: auto">
<p><figure>
<img decoding="async" src="https://percona.community/blog/2026/04/Jan-comic-neb.png" alt="&nbsp;"></figure>
</p>
</div>
<p>To avoid repeating this pattern, we (along with other vendors) are deliberately taking time before jumping into forks or immediate solutions. The goal is to find a sustainable, collaborative model rather than rushing into fragmentation.</p>
<p>For comparison, it took the Linux Foundation 6 days to respond to the <a href="https://github.com/redis/redis/pull/13157" target="_blank" rel="noopener noreferrer">Redis license change</a> by <a href="https://www.linuxfoundation.org/press/linux-foundation-launches-open-source-valkey-community" target="_blank" rel="noopener noreferrer">launching Valkey</a>. While this situation is different as there&rsquo;s no license change in pgBackRest, it illustrates that meaningful coordination takes time.</p>
<p>This is exactly where the open source community can demonstrate its strength.</p>
<h2 id="what-are-the-long-term-options">What are the long term options?<a class="anchor-link" id="what-are-the-long-term-options"></a></h2>
<p>This situation is particularly surprising to me personally, as I recently referenced David&rsquo;s proposed transparent funding model in <a href="https://www.postgresql.eu/events/pgconfde2026/" target="_blank" rel="noopener noreferrer">my talk</a> at <a href="http://pgconf.de/" target="_blank" rel="noopener noreferrer">PGConf.DE</a> just last week.</p>
<div style="width:30%;margin: auto">
<p><figure><img decoding="async" src="https://percona.community/blog/2026/04/Jan-david-money.png" alt="&nbsp;"></figure>
</p>
</div>
<p>The idea, distributing funding across organizations that rely on the project, seemed like a promising path toward a more sustainable ecosystem. In hindsight, it appears that adoption of this model was either too slow or insufficient to support ongoing maintenance.</p>
<p>Looking ahead, several long-term options are being discussed within the community:</p>
<ul>
<li>Establishing a foundation-backed project (similar to models used by <a href="https://codeberg.org/" target="_blank" rel="noopener noreferrer">Codeberg</a> or the Linux Foundation)</li>
<li>Creating a coordinated, multi-vendor stewardship model</li>
<li>In more extreme scenarios, moving critical tooling closer to the PostgreSQL core ecosystem</li>
</ul>
<p>These discussions are ongoing. If you&rsquo;re attending <a href="https://2026.pgconf.dev/" target="_blank" rel="noopener noreferrer">PGConf.Dev</a>, this will almost certainly be a major topic, especially in the extensions ecosystem track of community sessions in the <a href="https://2026.pgconf.dev/schedule/tuesday" target="_blank" rel="noopener noreferrer">Canfor</a> room on Tuesday.</p>
<h2 id="so-what-should-i-do-now">So what should I do now?<a class="anchor-link" id="so-what-should-i-do-now"></a></h2>
<div style="width:70%;margin: auto">
<p><figure>
<img decoding="async" src="https://percona.community/blog/2026/04/Jan-what-now.png" alt="&nbsp;"></figure>
</p>
</div>
<p>In short, nothing but wait. Yes, this means:</p>
<blockquote>
<p>Keep on using pgBackRest as you did!</p>
</blockquote>
<p>If your company is relying on pgBackRest, now is the time to engage. If you have capacity for this, please join the discussion (we&rsquo;ve kicked off a thread on <a href="https://forums.percona.com/t/pgbackrest-archival-discussion/40725?u=jan_wieremjewicz" target="_blank" rel="noopener noreferrer">Percona Community Forums</a> if you are looking for a place to join this topic)</p>
<p>Rest assured that you can follow the updates from us, we will be messaging about the progress made in regards to establishing the future for pgBackRest.</p>
<p>One thing to clear is: are there any immediate risks?</p>
<blockquote>
<p>Not new ones. There is the uncertainty that this is not a comfortable feeling. Rest assured that the longevity of the solution is not in jeopardy as we do have an obligation to our customer and user base to make sure the project is continued.</p>
</blockquote>

<p>The post <a rel="nofollow" href="https://percona.community/blog/2026/04/28/pgbackrest-is-archived-what-now/">pgBackRest is archived, what now?</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Database Trends: What is changing in the database world (besides AI)</title>
      <link>https://mariadb.org/database-trends-what-is-changing-in-the-database-world-besides-ai/</link>
      <pubDate>Mon, 27 Apr 2026 13:48:45 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.org/">MariaDB.org</source>
      <description><![CDATA[<p>Earlier this month, I had a half-hour chat with Kellyn Gorman, a Database and AI Advocate and Engineer at Redgate. …<br />
Continue reading \"Database Trends: What is changing in the database world (besides AI)\"<br />
The post Database Trends: What is changing in the database world (besides AI) appeared first on MariaDB.org.</p>
<p>The post <a rel="nofollow" href="https://mariadb.org/database-trends-what-is-changing-in-the-database-world-besides-ai/">Database Trends: What is changing in the database world (besides AI)</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>Earlier this month, I had a half-hour chat with <a href="https://www.red-gate.com/blog/author/kellyn-gorman/" target="_blank" rel="noreferrer noopener">Kellyn Gorman</a>, a Database and AI Advocate and Engineer at <a href="https://www.red-gate.com/" target="_blank" rel="noreferrer noopener">Redgate</a>. &hellip; </p>
<p class="link-more"><a href="https://mariadb.org/database-trends-what-is-changing-in-the-database-world-besides-ai/" class="more-link">Continue reading<span class="screen-reader-text"> &ldquo;Database Trends: What is changing in the database world (besides AI)&rdquo;</span></a></p>
<p>The post <a rel="nofollow" href="https://mariadb.org/database-trends-what-is-changing-in-the-database-world-besides-ai/">Database Trends: What is changing in the database world (besides AI)</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>

<p>The post <a rel="nofollow" href="https://mariadb.org/database-trends-what-is-changing-in-the-database-world-besides-ai/">Database Trends: What is changing in the database world (besides AI)</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Achieving High Availability with Valkey Sentinel</title>
      <link>https://www.percona.com/blog/achieving-high-availability-with-valkey-sentinel/</link>
      <pubDate>Fri, 24 Apr 2026 04:03:16 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://www.percona.com/blog/">Blog - Percona</source>
      <description><![CDATA[<p>In the previous guide, a robust Primary-Replica topology for Valkey was established. Read scaling is now active, and a hot copy of the data is securely stored on a second node. But there is a catch. If a primary node crashes, the replica will remain faithful and wait for instructions. It will not automatically take … Continued<br />
The post Achieving High Availability with Valkey Sentinel appeared first on Percona.</p>
<p>The post <a rel="nofollow" href="https://www.percona.com/blog/achieving-high-availability-with-valkey-sentinel/">Achieving High Availability with Valkey Sentinel</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p><span style="font-weight: 400">In the previous </span><a href="https://www.percona.com/blog/scaling-your-cache-a-step-by-step-guide-to-setting-up-valkey-replication/"><span style="font-weight: 400">guid</span></a><span style="font-weight: 400">e, a robust Primary-Replica topology for Valkey was established. Read scaling is now active, and a hot copy of the data is securely stored on a second node.</span></p>
<p><span style="font-weight: 400">But there is a catch. If a primary node crashes, the replica will remain faithful and wait for instructions. It will not automatically take over the responsibilities of the primary. Applications will start throwing write errors until an administrator manually logs in and reconfigures the replica to become the new primary.</span></p>
<p><span style="font-weight: 400">To achieve true High Availability (HA) and ensure continuous uptime without manual intervention, </span><b>Valkey Sentinel</b><span style="font-weight: 400"> is required.</span></p>
<h2><b>What is Valkey Sentinel?</b><a class="anchor-link" id="what-is-valkey-sentinel"></a></h2>
<p><span style="font-weight: 400">Valkey Sentinel is a distributed system designed to monitor Valkey instances, detect failures, and automatically handle failover.</span></p>
<p><span style="font-weight: 400">When Sentinel detects that a primary node is unresponsive, it performs the following tasks:</span></p>
<ol>
<li style="font-weight: 400"><b>Monitoring:</b><span style="font-weight: 400"> It continuously checks whether primary and replica nodes are functioning as expected.</span></li>
<li style="font-weight: 400"><b>Notification:</b><span style="font-weight: 400"> It can notify system administrators or another computer program via an API that something is wrong.</span></li>
<li style="font-weight: 400"><b>Automatic Failover:</b><span style="font-weight: 400"> It promotes a healthy replica to the new primary and reconfigures the other replicas to sync with it.</span></li>
<li style="font-weight: 400"><b>Configuration Provider:</b><span style="font-weight: 400"> It acts as a source of truth for clients. Applications can connect to Sentinel to ask for the current primary&rsquo;s address. If a failover occurs, Sentinel reports the new address.</span></li>
</ol>
<h2><b>The Rule of Three (Quorum)</b><a class="anchor-link" id="the-rule-of-three-quorum"></a></h2>
<p><span style="font-weight: 400">Sentinel is a distributed system, meaning multiple Sentinel processes must run and agree on a node&rsquo;s failure before taking action. This agreement is called a </span><b>quorum</b><span style="font-weight: 400">.</span></p>
<p><span style="font-weight: 400">To prevent a &ldquo;split-brain&rdquo; scenario (where a network partition causes two nodes to both assume they are the primary), </span><b>at least three Sentinel instances</b><span style="font-weight: 400"> must be deployed.</span></p>
<p><span style="font-weight: 400">For this guide, the environment consists of three dedicated database nodes. Each node will run both the Valkey database service and the Valkey Sentinel service:</span></p>
<ul>
<li style="font-weight: 400"><b>ArunValkeyPrimary (Primary + Sentinel):</b> <span style="font-weight: 400">172.31.32.27</span></li>
<li style="font-weight: 400"><b>ArunValkeyReplica (Replica 1 + Sentinel):</b> <span style="font-weight: 400">172.31.37.55</span></li>
<li style="font-weight: 400"><b>ArunValkeyReplica2 (Replica 2 + Sentinel):</b> <span style="font-weight: 400">172.31.39.58</span></li>
</ul>
<p><span style="font-weight: 400">The primary node is healthy and running as the master, with two replicas connected and actively syncing.</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">root@ArunValkeyPrimary:/home/ubuntu# valkey-cli -a amma@123

Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.

127.0.0.1:6379&gt; INFO replication

# Replication

role:master

connected_slaves:2

slave0:ip=172.31.37.55,port=6379,state=online,offset=98214,lag=1

slave1:ip=172.31.39.58,port=6379,state=online,offset=98214,lag=1

master_failover_state:no-failover

master_replid:629656a198b7290bf6492e470b449ad1ced509e0

master_replid2:30977276632877f46ad12fcc2bbc2c5191c67c0c

master_repl_offset:98214

second_repl_offset:1643

repl_backlog_active:1

repl_backlog_size:1048576

repl_backlog_first_byte_offset:1643

repl_backlog_histlen:96572

127.0.0.1:6379&gt;</pre>

<h2><b>Step 1: Create the Sentinel Configuration File</b><a class="anchor-link" id="step-1-create-the-sentinel-configuration-file"></a></h2>
<p><span style="font-weight: 400">Sentinel runs as a separate process from the main Valkey database, using its own configuration file and listening on port </span><span style="font-weight: 400">26379</span><span style="font-weight: 400"> by default.</span></p>
<p><span style="font-weight: 400">The Sentinel configuration file (typically </span><span style="font-weight: 400">/etc/valkey/sentinel.conf</span><span style="font-weight: 400">) must be created or edited on </span><b>all three nodes</b><span style="font-weight: 400">(</span><span style="font-weight: 400">ArunValkeyPrimary</span><span style="font-weight: 400">, </span><span style="font-weight: 400">ArunValkeyReplica</span><span style="font-weight: 400">, and </span><span style="font-weight: 400">ArunValkeyReplica2</span><span style="font-weight: 400">).</span></p>
<p><span style="font-weight: 400">Open the file and add the following core directives:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">port 26379
# Format: sentinel monitor &lt;cluster-name&gt; &lt;primary-ip&gt; &lt;primary-port&gt; &lt;quorum&gt;
sentinel monitor mymaster 172.31.32.27 6379 2

# The primary password set in the previous setup
sentinel auth-user mymaster default

sentinel auth-pass mymaster amma@123

# How many milliseconds the primary must be unreachable before Sentinel considers it down
sentinel down-after-milliseconds mymaster 5000

# How long to wait before trying another failover if the first one fails
sentinel failover-timeout mymaster 10000</pre>
<p><b>Understanding the </b><b>monitor</b><b> line:</b></p>
<ul>
<li style="font-weight: 400"><span style="font-weight: 400">mymaster</span><span style="font-weight: 400"> is the arbitrary name given to this cluster.</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">172.31.32.27 6379</span><span style="font-weight: 400"> points to the current primary node (</span><span style="font-weight: 400">ArunValkeyPrimary</span><span style="font-weight: 400">). (Sentinels will automatically discover both replicas by querying the primary, so the replica IPs do not need to be listed).</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">2</span><span style="font-weight: 400"> is the quorum. This means at least 2 out of the 3 Sentinels must agree the primary is down to initiate a failover.</span></li>
</ul>
<h2><b>Step 2: Ensure Proper Permissions</b><a class="anchor-link" id="step-2-ensure-proper-permissions"></a></h2>
<p><span style="font-weight: 400">Sentinel needs the ability to rewrite its own configuration file. When a failover happens, Sentinel updates </span><span style="font-weight: 400">sentinel.conf</span><span style="font-weight: 400"> with the new primary&rsquo;s IP address and the current state of the cluster.</span></p>
<p><span style="font-weight: 400">Ensure the </span><span style="font-weight: 400">valkey</span><span style="font-weight: 400"> user has write permissions to the file on all three nodes:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">sudo chown valkey:valkey /etc/valkey/sentinel.conf</pre>

<h2><b>Step 3: Start the Sentinel Services</b><a class="anchor-link" id="step-3-start-the-sentinel-services"></a></h2>
<p><span style="font-weight: 400">Start the Sentinel service on all three nodes. Depending on the Linux distribution and the Valkey installation method, this is usually done via </span><span style="font-weight: 400">systemctl</span><span style="font-weight: 400">:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">root@ArunValkeyPrimary:/home/ubuntu# sudo systemctl enable valkey-sentinel
Synchronizing state of valkey-sentinel.service with SysV service script with /usr/lib/systemd/systemd-sysv-install.
Executing: /usr/lib/systemd/systemd-sysv-install enable valkey-sentinel
root@ArunValkeyPrimary:/home/ubuntu# sudo systemctl start valkey-sentinel
root@ArunValkeyPrimary:/home/ubuntu#


root@ArunValkeyReplica:/home/ubuntu# sudo systemctl enable valkey-sentinel
Synchronizing state of valkey-sentinel.service with SysV service script with /usr/lib/systemd/systemd-sysv-install.
Executing: /usr/lib/systemd/systemd-sysv-install enable valkey-sentinel
root@ArunValkeyReplica:/home/ubuntu# sudo systemctl start valkey-sentinel
root@ArunValkeyReplica:/home/ubuntu#

root@ArunValkeyReplica2:/home/ubuntu# sudo systemctl enable valkey-sentinel
Synchronizing state of valkey-sentinel.service with SysV service script with /usr/lib/systemd/systemd-sysv-install.
Executing: /usr/lib/systemd/systemd-sysv-install enable valkey-sentinel
root@ArunValkeyReplica2:/home/ubuntu# sudo systemctl start valkey-sentinel
root@ArunValkeyReplica2:/home/ubuntu#</pre>

<h2><b>Step 4: Verify the Sentinel Cluster</b><a class="anchor-link" id="step-4-verify-the-sentinel-cluster"></a></h2>
<p><span style="font-weight: 400">Check if the Sentinels are successfully communicating with each other and monitoring the database. Log into any node and use the Valkey CLI to connect to the Sentinel port (</span><span style="font-weight: 400">26379</span><span style="font-weight: 400">):</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">root@ArunValkeyPrimary:/home/ubuntu# valkey-cli -p 26379
AUTH failed: ERR AUTH &lt;password&gt; called without any password configured for the default user. Are you sure your configuration is correct?
127.0.0.1:26379&gt; INFO sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_tilt_since_seconds:-1
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=172.31.32.27:6379,slaves=2,sentinels=3
127.0.0.1:26379&gt;</pre>
<p><span style="font-weight: 400">Look closely at the </span><span style="font-weight: 400">master0</span><span style="font-weight: 400"> line at the bottom. This confirms everything is functioning correctly:</span></p>
<ul>
<li style="font-weight: 400"><span style="font-weight: 400">status=ok</span><span style="font-weight: 400">: The primary (</span><span style="font-weight: 400">ArunValkeyPrimary</span><span style="font-weight: 400">) is healthy.</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">slaves=2</span><span style="font-weight: 400">: Sentinel found both </span><span style="font-weight: 400">ArunValkeyReplica</span><span style="font-weight: 400"> and </span><span style="font-weight: 400">ArunValkeyReplica2</span><span style="font-weight: 400">.</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">sentinels=3</span><span style="font-weight: 400">: All three Sentinel instances have discovered each other and formed a quorum.</span></li>
</ul>
<h4><b>Additional Verification: Sentinel Peer Health</b></h4>
<p><span style="font-weight: 400">To further validate that all Sentinel nodes are actively communicating and healthy, we can query the list of Sentinel peers and inspect their status:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">root@ArunValkeyPrimary:/home/ubuntu# valkey-cli -p 26379 SENTINEL SENTINELS mymaster | grep -E -A 1 '^ip$|^flags$|^last-ok-ping-reply$|^down-after-milliseconds$'
ip
172.31.37.55
--
flags
sentinel
--
last-ok-ping-reply
65
--
down-after-milliseconds
5000
--
ip
172.31.39.58
--
flags
sentinel
--
last-ok-ping-reply
65
--
down-after-milliseconds
5000
root@ArunValkeyPrimary:/home/ubuntu#</pre>

<h3><b>What this means:</b><a class="anchor-link" id="what-this-means"></a></h3>
<ul>
<li style="font-weight: 400"><b>ip</b><span style="font-weight: 400"> &rarr; Lists the other Sentinel nodes in the cluster</span></li>
<li style="font-weight: 400"><b>flags=sentinel</b><span style="font-weight: 400"> &rarr; Confirms these are active Sentinel peers</span></li>
<li style="font-weight: 400"><b>last-ok-ping-reply</b><span style="font-weight: 400"> &rarr; Indicates the last successful heartbeat response (in milliseconds)</span></li>
<li style="font-weight: 400"><b>down-after-milliseconds: 5000 ms</b><span style="font-weight: 400"> &rarr; failure threshold</span></li>
</ul>
<p><span style="font-weight: 400">Lower values here indicate </span><b>healthy and responsive communication</b><span style="font-weight: 400"> between Sentinel nodes.</span></p>
<h2><b>Step 5: The Chaos Test (Triggering a Failover)</b><a class="anchor-link" id="step-5-the-chaos-test-triggering-a-failover"></a></h2>
<p><span style="font-weight: 400">The best way to trust an HA setup is to break it intentionally. We will simulate a crash by killing the primary node, verifying the failover, and then manually failing back to our original primary.</span></p>
<h3><b>1. Kill the Primary</b><a class="anchor-link" id="1-kill-the-primary"></a></h3>
<p><span style="font-weight: 400">On </span><b>ArunValkeyPrimary</b><span style="font-weight: 400"> (</span><span style="font-weight: 400">172.31.32.27</span><span style="font-weight: 400">), stop the Valkey database service (do not stop Sentinel, just the database):</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">root@ArunValkeyPrimary:/home/ubuntu# sudo systemctl stop valkey
root@ArunValkeyPrimary:/home/ubuntu#</pre>

<h3><b>2. Verify the Failover via Sentinel</b><a class="anchor-link" id="2-verify-the-failover-via-sentinel"></a></h3>
<p><span style="font-weight: 400">Wait for about 5 to 10 seconds to allow the </span><span style="font-weight: 400">down-after-milliseconds</span><span style="font-weight: 400"> threshold to pass and the Sentinels to complete the election process. Instead of checking the logs, you can query the Sentinel information directly to confirm the failover has occurred and find out which node was promoted.</span></p>
<p><span style="font-weight: 400">On </span><b>ArunValkeyReplica</b><span style="font-weight: 400">, connect to the Sentinel port (</span><span style="font-weight: 400">26379</span><span style="font-weight: 400">) and run the </span><span style="font-weight: 400">INFO sentinel</span><span style="font-weight: 400"> command:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">root@ArunValkeyReplica:/home/ubuntu# valkey-cli -p 26379
127.0.0.1:26379&gt; INFO sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_tilt_since_seconds:-1
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=172.31.37.55:6379,slaves=2,sentinels=3
127.0.0.1:26379&gt;</pre>
<p><span style="font-weight: 400">Look at the </span><span style="font-weight: 400">master0</span><span style="font-weight: 400"> line at the bottom. It shows that the status is </span><span style="font-weight: 400">ok</span><span style="font-weight: 400"> and the primary address is now </span><b>172.31.37.55:6379</b><span style="font-weight: 400">.</span></p>
<h3><b>3. Verify the Failover via the Database</b><a class="anchor-link" id="3-verify-the-failover-via-the-database"></a></h3>
<p><span style="font-weight: 400">Now, connect to that newly promoted node (</span><span style="font-weight: 400">172.31.37.55</span><span style="font-weight: 400">) on the standard database port to verify the promotion from the database&rsquo;s perspective:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">root@ArunValkeyReplica:/home/ubuntu# valkey-cli -a amma@123
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379&gt; INFO replication
# Replication
role:master
connected_slaves:1
slave0:ip=172.31.39.58,port=6379,state=online,offset=574633,lag=0
master_failover_state:no-failover
master_replid:b93b82982616a59a2304a799e548d7398ee15732
master_replid2:43ea3aeca4846f06c3c6dd11174e9bfd7ac7fabf
master_repl_offset:574633
second_repl_offset:475110
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:450256
repl_backlog_histlen:124378
127.0.0.1:6379&gt;</pre>
<p><span style="font-weight: 400">Notice that the </span><span style="font-weight: 400">role</span><span style="font-weight: 400"> has changed from </span><span style="font-weight: 400">slave</span><span style="font-weight: 400"> to </span><span style="font-weight: 400">master</span><span style="font-weight: 400">, and it now shows </span><span style="font-weight: 400">1</span><span style="font-weight: 400"> connected slave (the other surviving replica, </span><span style="font-weight: 400">172.31.39.58</span><span style="font-weight: 400">).</span></p>
<h3><b>4. Restarting the Old Primary</b><a class="anchor-link" id="4-restarting-the-old-primary"></a></h3>
<p><span style="font-weight: 400">When the Valkey service on </span><b>ArunValkeyPrimary</b><span style="font-weight: 400"> is eventually restarted, Sentinel will automatically detect it, reconfigure it as a read-only replica, and point it to the newly promoted primary to catch up on missed data.</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">root@ArunValkeyPrimary:/home/ubuntu# sudo systemctl start valkey
root@ArunValkeyPrimary:/home/ubuntu# valkey-cli -p 26379 INFO sentinel
AUTH failed: ERR AUTH &lt;password&gt; called without any password configured for the default user. Are you sure your configuration is correct?
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_tilt_since_seconds:-1
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=172.31.37.55:6379,slaves=2,sentinels=3</pre>
<p><span style="font-weight: 400">Check the database replication status on the old primary to see it is now acting as a replica:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">root@ArunValkeyPrimary:/home/ubuntu# valkey-cli INFO replication
# Replication
role:slave
master_host:172.31.37.55
master_port:6379
master_link_status:up
master_last_io_seconds_ago:0
master_sync_in_progress:0
slave_read_repl_offset:614120
slave_repl_offset:614120
slave_priority:1
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:b93b82982616a59a2304a799e548d7398ee15732
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:614120
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:607384
repl_backlog_histlen:6737
root@ArunValkeyPrimary:/home/ubuntu#</pre>

<h3><b>5. Executing a Manual Failback</b><a class="anchor-link" id="5-executing-a-manual-failback"></a></h3>
<p><span style="font-weight: 400">If you want </span><b>ArunValkeyPrimary</b><span style="font-weight: 400"> to reclaim its throne as the primary node, you can trigger a manual failover. First, configure it to have a high priority for elections, then issue the failover command to Sentinel:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">root@ArunValkeyPrimary:/home/ubuntu# valkey-cli CONFIG SET replica-priority 1
OK
root@ArunValkeyPrimary:/home/ubuntu# valkey-cli CONFIG REWRITE
OK
root@ArunValkeyPrimary:/home/ubuntu# valkey-cli -p 26379 SENTINEL FAILOVER mymaster
AUTH failed: ERR AUTH &lt;password&gt; called without any password configured for the default user. Are you sure your configuration is correct?
OK</pre>
<p><i><span style="font-weight: 400">(Note: The AUTH failed warnings simply indicate the CLI attempted to pass a default auth to a Sentinel instance that might not require it or is configured differently, but the </span></i><i><span style="font-weight: 400">OK</span></i><i><span style="font-weight: 400"> confirms the command successfully executed.)</span></i></p>
<p><span style="font-weight: 400">Check Sentinel one last time to confirm </span><span style="font-weight: 400">ArunValkeyPrimary</span><span style="font-weight: 400"> (</span><span style="font-weight: 400">172.31.32.27</span><span style="font-weight: 400">) is back in charge:</span><b></b></p>
<pre class="urvanov-syntax-highlighter-plain-tag">root@ArunValkeyPrimary:/home/ubuntu# valkey-cli -p 26379 INFO sentinel

AUTH failed: ERR AUTH &lt;password&gt; called without any password configured for the default user. Are you sure your configuration is correct?
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_tilt_since_seconds:-1
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=172.31.32.27:6379,slaves=2,sentinels=3
root@ArunValkeyPrimary:/home/ubuntu#</pre>
<p><b>Wrapping Up</b></p>
<p><span style="font-weight: 400">By combining replication with Sentinel, a single cache becomes a highly available, self-healing data cluster. If hardware fails or network hiccups occur, Sentinel automatically handles the reshuffling. Furthermore, as demonstrated, system administrators still retain full control to manually shuffle roles during planned maintenance or load balancing.</span></p>
<p>The post <a href="https://www.percona.com/blog/achieving-high-availability-with-valkey-sentinel/">Achieving High Availability with Valkey Sentinel</a> appeared first on <a href="https://www.percona.com">Percona</a>.</p>

<p>The post <a rel="nofollow" href="https://www.percona.com/blog/achieving-high-availability-with-valkey-sentinel/">Achieving High Availability with Valkey Sentinel</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Innovation From Every Corner: Inside Percona’s Build with AI Competition</title>
      <link>https://www.percona.com/blog/innovation-from-every-corner-inside-perconas-build-with-ai-competition/</link>
      <pubDate>Thu, 23 Apr 2026 18:53:00 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://www.percona.com/blog/">Blog - Percona</source>
      <description><![CDATA[<p>At Percona, we’re passionate about open source database software, helping organizations of all sizes run, manage, and optimize their databases with the freedom and transparency that open source provides. That spirit of openness doesn’t stop at our products, it runs through everything we do, including how we encourage our own people to innovate. We recently … Continued<br />
The post Innovation From Every Corner: Inside Percona’s Build with AI Competition appeared first on Percona.</p>
<p>The post <a rel="nofollow" href="https://www.percona.com/blog/innovation-from-every-corner-inside-perconas-build-with-ai-competition/">Innovation From Every Corner: Inside Percona’s Build with AI Competition</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p><span style="font-weight: 400">At Percona, we&rsquo;re passionate about open source database software, helping organizations of all sizes run, manage, and optimize their databases with the freedom and transparency that open source provides. That spirit of openness doesn&rsquo;t stop at our products, it runs through everything we do, including how we encourage our own people to innovate.</span></p>
<p><span style="font-weight: 400">We recently ran a 6-week &ldquo;Build with AI&rdquo; competition here at Percona, where we invited all Perconians to use their AI technology/tool of choice to solve a problem, create something new, or improve a product or internal process that they felt was worth improving.&nbsp;</span></p>
<p><span style="font-weight: 400">In the spirit of our belief that </span><b>The Way Is Open</b><span style="font-weight: 400">, that open source should mean real freedom, not lock-in, inflated costs, or hollow promises, we encouraged as much transparency as possible sharing ideas with colleagues, and where appropriate with the community as well. &ldquo;</span><b><i>Default to building in open</i></b><span style="font-weight: 400">&rdquo; was the guideline.</span></p>
<p>&nbsp;</p>
<h2><b>The Rules</b><a class="anchor-link" id="the-rules"></a></h2>
<p><span style="font-weight: 400">The rules were simple and minimal.</span></p>
<ol>
<li style="font-weight: 400"><span style="font-weight: 400">Do whatever you like. Whether that&rsquo;s building new products or features that our customers and community will value, creating internal tools that help us work smarter and faster, improving our customer experience, or even tearing down processes and workflows that have outlived their usefulness.</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Use whichever tool you want &ndash; our Percona-approved AI toolset, or other tools we haven&rsquo;t bought en masse (yet). Expense your token spending if needed &ndash; we&rsquo;ll cover the cost.&nbsp;</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Submit as many times as you like &ndash; multiple projects are welcome</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Keep our compliance &amp; governance policies in mind around customer/confidential data, we want to build responsibly.</span></li>
</ol>
<p>&nbsp;</p>
<p><span style="font-weight: 400">The Top 3 (as judged by our competition judges, Peter Farkas (CEO), Peter Zaitsev (Founder), Vadim Tkachenko (Co-Founder), and me (COO) would win prizes.&nbsp;</span></p>
<p><span style="font-weight: 400">It&rsquo;s easy to forget the breadth of talent and innovative ideas we have at Percona. I am fiercely proud to say that we&rsquo;re surrounded by the best of the best every day, and I say it often to customers, partners, and colleagues. This competition was a great reminder! </span><span style="font-weight: 400">We had over 40 submissions from across the company, and from Perconians in 10+ teams. We saw representation from our Customer Success, Support, Engineering, Marketing, Product Management, Community, Legal and Contracts team, Professional and Managed Services teams, and more.&nbsp;</span></p>
<p><span style="font-weight: 400">We ran into two stereotypical &ldquo;great problems to have&rdquo;:</span></p>
<p><span style="font-weight: 400">First,&nbsp; we scheduled an entire day for the demos and presentations, and it wasn&rsquo;t enough time. Fortunately, we found extra time pretty quickly.&nbsp;</span></p>
<p><span style="font-weight: 400">Second &ndash; it was simply impossible to pick only 3 winners! There were just too many great ideas, so we had to get creative&hellip;</span></p>
<p>&nbsp;</p>
<h2><b>The Winners</b><a class="anchor-link" id="the-winners"></a></h2>
<p><span style="font-weight: 400">After a tough deliberation, here&rsquo;s how our judges landed:</span></p>
<p><span style="font-weight: 400">With no further ado, the first-place winner was Tibi Korocz (Observability Tech Lead). Tibi extended PMM to become an </span><b>AI-assisted incident workspace</b><span style="font-weight: 400">, helping users not only understand their database environment better but also receive intelligent insights and real recommendations to improve, optimize, and fix issues. It&rsquo;s also integrated with Percona Services, improving customer experience through integration with our ServiceNow platform. It&rsquo;s a deserving winner and is worthy of its own blog post, which Tibi will publish (this article will be updated with the link)</span></p>
<p><span style="font-weight: 400">Second was Dennis Kittrell (head of MySQL product &amp; engineering). Dennis built a suite of open-source tools &mdash; including connectors for an internally hosted AI assistant that integrate Slack, Notion, Jira, and ServiceNow, and a local semantic search engine for Percona documentation &mdash; that together give Perconians smarter, faster access to the knowledge they need every day.</span></p>
<p><span style="font-weight: 400">Third place was Agustin Gallego (Lead Database Performance Engineer), who built a Postgres extension that produces pt-query-digest-compatible slow query logs with extended PostgreSQL-specific metrics, inspired by Agustin&rsquo;s vast MySQL experience and his belief that &ldquo;</span><i><span style="font-weight: 400">thinking about Percona Server&rsquo;s extended slow logging capabilities and pt-query-digest, I&rsquo;ve always felt we could do better in Postgres.&rdquo;</span></i></p>
<p>&nbsp;</p>
<h2><b>Special Recognition Awards</b><a class="anchor-link" id="special-recognition-awards"></a></h2>
<p><span style="font-weight: 400">We also recognized the following:</span></p>
<p><strong>Community Impact Award</strong><span style="font-weight: 400"> to Zsolt Parragi and Kai Wagner (Postgres Engineering team), for their </span><a href="https://hackorum.dev"><span style="font-weight: 400">hackorum.dev</span></a><span style="font-weight: 400"> site. A new frontend for the pgsql hackers mailing list, something that has been missing in the community for a long time, and is already live. Check it out!</span></p>
<p><strong>AI Transformation Award</strong><span style="font-weight: 400"> to Scott LaFortune and Kim Reddy (Marketing team), who built an internal platform for managing and creating materials (content, copy, campaigns, etc) that specifically encodes Percona&rsquo;s brand voice and compliance rules so any Percona marketer gets on-brand output without needing to know how to prompt Claude, and kick-starts the AI transformation of our marketing team.</span></p>
<p><strong>The Dare to Try</strong><span style="font-weight: 400"> award went to Molly Fulton in our contracts and legal team, who wanted to &ldquo;</span><i><span style="font-weight: 400">pressure test the idea that &ldquo;anyone can enter&rdquo; and represent non-technical Perconians in this challenge</span></i><span style="font-weight: 400">&rdquo;, and she did it by building a tool to help Perconians learn more about how our contracts team identifies and mitigates risk for our customers!</span></p>
<p><span style="font-weight: 400">Congratulations to all of our winners! And also to all of our submissions &ndash; it was difficult to pick the winners, and we have decided that we are going to run this competition again later in the year. It was simply too good to be a one-time thing. A lot of the projects are going to continue and likely turn into full initiatives &ndash; I expect we will have more blog posts about them in the coming weeks and months.</span></p>
<p><span style="font-weight: 400">Of course, I couldn&rsquo;t finish this post without making a small request. If this is the sort of thing that excites you and you want to be at a company that encourages, embraces, and rewards this sort of innovation and experimentation, check out our </span><a href="https://www.percona.com/careers/"><span style="font-weight: 400">careers page</span></a><span style="font-weight: 400"> and join us!&nbsp;</span></p>
<p>The post <a href="https://www.percona.com/blog/innovation-from-every-corner-inside-perconas-build-with-ai-competition/">Innovation From Every Corner: Inside Percona&rsquo;s Build with AI Competition</a> appeared first on <a href="https://www.percona.com">Percona</a>.</p>

<p>The post <a rel="nofollow" href="https://www.percona.com/blog/innovation-from-every-corner-inside-perconas-build-with-ai-competition/">Innovation From Every Corner: Inside Percona’s Build with AI Competition</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>A Clearer Path Forward for GridGain Customers</title>
      <link>https://mariadb.com/resources/blog/a-clearer-path-forward-for-gridgain-customers/</link>
      <pubDate>Thu, 23 Apr 2026 17:12:13 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.com/">MariaDB</source>
      <description><![CDATA[<p>This blog was originally published on GridGain’s website. When MariaDB evaluated and acquired GridGain, we noticed something important: GridGain is […]</p>
<p>The post <a rel="nofollow" href="https://mariadb.com/resources/blog/a-clearer-path-forward-for-gridgain-customers/">A Clearer Path Forward for GridGain Customers</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>This blog was originally published on GridGain&rsquo;s website. When MariaDB evaluated and acquired GridGain, we noticed something important: GridGain is not a platform used on the margins of an enterprise, instead it sits at the heart of systems that matter deeply to the business. Customers rely on it for payments, fraud prevention, risk management, customer 360, and other applications where ultra&hellip;</p>
<p><a href="https://mariadb.com/resources/blog/a-clearer-path-forward-for-gridgain-customers/" rel="nofollow">Source</a></p>

<p>The post <a rel="nofollow" href="https://mariadb.com/resources/blog/a-clearer-path-forward-for-gridgain-customers/">A Clearer Path Forward for GridGain Customers</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Scaling Your Cache: A Step-by-Step Guide to Setting Up Valkey Replication</title>
      <link>https://www.percona.com/blog/scaling-your-cache-a-step-by-step-guide-to-setting-up-valkey-replication/</link>
      <pubDate>Thu, 23 Apr 2026 16:46:27 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://www.percona.com/blog/">Blog - Percona</source>
      <description><![CDATA[<p>In the recent open-source data landscape, Valkey has emerged as a prominent player. Born as a Linux Foundation-backed, fully open-source fork of Redis (following Redis’s recent licensing changes), Valkey serves as a high-performance, in-memory key-value data store. Whether Valkey is deployed as a primary database, an ephemeral cache, or a rapid message broker, a single … Continued<br />
The post Scaling Your Cache: A Step-by-Step Guide to Setting Up Valkey Replication appeared first on Percona.</p>
<p>The post <a rel="nofollow" href="https://www.percona.com/blog/scaling-your-cache-a-step-by-step-guide-to-setting-up-valkey-replication/">Scaling Your Cache: A Step-by-Step Guide to Setting Up Valkey Replication</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p><span style="font-weight: 400">In the recent open-source data landscape, Valkey has emerged as a prominent player. Born as a Linux Foundation-backed, fully open-source fork of Redis (following Redis&rsquo;s recent licensing changes), Valkey serves as a high-performance, in-memory key-value data store.</span></p>
<p><span style="font-weight: 400">Whether Valkey is deployed as a primary database, an ephemeral cache, or a rapid message broker, a single node is rarely sufficient for production workloads, as it creates a single point of failure. Ensuring high availability and scaling out read operations requires replication.</span></p>
<p><span style="font-weight: 400">This comprehensive guide explores how to configure a Primary-Replica (Master-Slave) replication topology in Valkey, detailing its underlying mechanics and the verification process.</span></p>
<h2><b>How Valkey Replication Works</b><a class="anchor-link" id="how-valkey-replication-works"></a></h2>
<p><span style="font-weight: 400">Valkey&rsquo;s replication is asynchronous and non-blocking. When a replica connects to a primary node, it initiates a synchronisation process.</span></p>
<p><span style="font-weight: 400">Initially, the primary creates a snapshot of its entire dataset in memory (an RDB file) and sends it to the replica. Once this initial full sync is complete, the primary continuously streams a log of all new write operations to the replica. Because this happens asynchronously, the primary node does not wait for the replica to acknowledge writes, meaning applications experience zero latency penalty from the replication process.</span></p>
<h2><b>Why Use Replication?</b><a class="anchor-link" id="why-use-replication"></a></h2>
<p><span style="font-weight: 400">Before diving into the configuration commands, it is important to understand the concrete benefits of this architecture:</span></p>
<ul>
<li style="font-weight: 400"><b>Data Redundancy: </b><span style="font-weight: 400">Replication maintains a near real-time copy of the data on replicas. However, because replication is asynchronous, there may be a small delay, and recent writes might not be fully replicated at the moment of a primary failure. For applications requiring stronger durability guarantees, the </span><span style="font-weight: 400">WAIT</span><span style="font-weight: 400"> command can be used to ensure that writes are acknowledged by one or more replicas.</span></li>
<li style="font-weight: 400"><b>Read Scaling:</b><span style="font-weight: 400"> Heavy read operations (like </span><span style="font-weight: 400">GET</span><span style="font-weight: 400"> or </span><span style="font-weight: 400">LRANGE</span><span style="font-weight: 400"> commands) can be offloaded to replicas. This frees up the primary node to dedicate its CPU and network bandwidth to handling write operations efficiently.</span></li>
<li style="font-weight: 400"><b>High Availability:</b><span style="font-weight: 400"> When paired with Valkey Sentinel or a cluster manager, replication forms the foundational layer for automatic failover.</span></li>
</ul>
<h2><b>Prerequisites</b><a class="anchor-link" id="prerequisites"></a></h2>
<p><span style="font-weight: 400">The following components are required:</span></p>
<ul>
<li style="font-weight: 400"><span style="font-weight: 400">Two servers, virtual machines, or containers with Valkey installed.</span></li>
<li style="font-weight: 400"><b>Network connectivity:</b><span style="font-weight: 400"> The replica must be able to reach the primary on its Valkey port. Ensure firewalls (UFW, iptables) or cloud security groups (AWS, GCP) allow TCP traffic on port 6379 between the specified IPs.</span></li>
</ul>
<p><span style="font-weight: 400">This tutorial uses the following hypothetical IP addresses:</span></p>
<ul>
<li style="font-weight: 400"><b>Primary Node:</b><span style="font-weight: 400"> 172.31.32.27</span></li>
<li style="font-weight: 400"><b>Replica Node:</b><span style="font-weight: 400"> 172.31.37.55</span></li>
<li style="font-weight: 400"><b>Valkey Port:</b><span style="font-weight: 400"> 6379 (the default)</span></li>
</ul>
<h2><b>Step 1: Configure the Primary Node</b><a class="anchor-link" id="step-1-configure-the-primary-node"></a></h2>
<p><span style="font-weight: 400">By default, Valkey binds only to localhost (127.0.0.1), meaning it rejects connections from outside servers. This must be adjusted to allow replica connections.</span></p>
<ol>
<li><span style="font-weight: 400"> Open the Valkey configuration file on the Primary Node (typically located at </span><span style="font-weight: 400">/etc/valkey/valkey.conf</span><span style="font-weight: 400">, depending on the installation method).</span></li>
</ol>
<p><span style="font-weight: 400">&nbsp; &nbsp; &nbsp; 2. Find the </span><span style="font-weight: 400">bind</span><span style="font-weight: 400"> directive. Update it to listen on both localhost and the internal network IP. Note: While </span><span style="font-weight: 400">*</span><span style="font-weight: 400"> can be used to listen on all interfaces, specifying the exact IP provides better security.</span></p>
<p><span style="font-weight: 400">bind 127.0.0.1 </span><span style="font-weight: 400">172.31.32.27</span></p>
<ol start="3">
<li>Configure ACLs (Access Control Lists) for Security and Replication:</li>
</ol>
<p><span style="font-weight: 400">&nbsp;While older versions of Redis used the </span><span style="font-weight: 400">requirepass</span><span style="font-weight: 400"> directive, Valkey utilizes modern ACLs. Securing the default user and creating a dedicated, restricted user specifically for replication is highly recommended. This ensures the replica only has the permissions necessary to sync data. Add the following ACL rules:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag"># Secure the default user so unauthorized users cannot access the database
user default on &gt;amma@123 ~* &amp;* +@all

# Create a dedicated replication user with ONLY the permissions needed to sync
user repl_user on &gt;ReplPass@123 -@all +psync +replconf +ping +info</pre>

<ol start="4">
<li><span style="font-weight: 400"> Restart the Valkey service to apply the changes:</span></li>
</ol>
<pre class="urvanov-syntax-highlighter-plain-tag">sudo systemctl restart valkey</pre>

<h2><b>Step 2: Configure the Replica Node</b><a class="anchor-link" id="step-2-configure-the-replica-node"></a></h2>
<p><span style="font-weight: 400">Now, let&rsquo;s move over to the Replica Node (</span><span style="font-weight: 400">172.31.37.55</span><span style="font-weight: 400">). There are two ways to configure a replica: dynamically via the CLI using the </span><span style="font-weight: 400">REPLICAOF</span><span style="font-weight: 400"> command (which resets upon reboot) or permanently via the configuration file. For production, we will use the permanent method.</span></p>
<ol>
<li><span style="font-weight: 400"> Open the Valkey configuration file on the Replica.</span></li>
<li><span style="font-weight: 400"> Locate the </span><span style="font-weight: 400">replicaof</span><span style="font-weight: 400"> directive (in older versions or Redis compat mode, this might be </span><span style="font-weight: 400">slaveof</span><span style="font-weight: 400">). Uncomment it and add the Primary&rsquo;s IP and port:</span></li>
</ol>
<pre class="urvanov-syntax-highlighter-plain-tag">replicaof 172.31.32.27 6379</pre>

<ol start="3">
<li><b> Authenticate using the Replication ACL:</b><span style="font-weight: 400"> Because a dedicated </span><span style="font-weight: 400">repl_user</span><span style="font-weight: 400"> was created on the primary node, the replica must be configured to use those specific credentials. Find the </span><span style="font-weight: 400">masteruser</span><span style="font-weight: 400"> and </span><span style="font-weight: 400">masterauth</span><span style="font-weight: 400"> directives and update them:</span></li>
</ol>
<pre class="urvanov-syntax-highlighter-plain-tag">masteruser repl_user
masterauth ReplPass@123</pre>

<ol start="4">
<li><i><span style="font-weight: 400">(Optional but recommended)</span></i><span style="font-weight: 400"> Ensure the replica is strictly read-only by checking this directive:</span></li>
</ol>
<pre class="urvanov-syntax-highlighter-plain-tag">replica-read-only yes</pre>
<p><span style="font-weight: 400">Restart the Valkey service on the replica:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">sudo systemctl restart valkey</pre>

<h2><b>Step 3: Verify the Replication</b><a class="anchor-link" id="step-3-verify-the-replication"></a></h2>
<p><span style="font-weight: 400">The replica should now be connecting to the primary and synchronizing the dataset. Let&rsquo;s verify the connection and test the data flow.</span></p>
<h3><b>Checking Replication Status</b><a class="anchor-link" id="checking-replication-status"></a></h3>
<p><span style="font-weight: 400">Log in to the </span><b>Primary Node</b><span style="font-weight: 400"> using the Valkey CLI.</span></p>
<p><b>Pro tip:</b><span style="font-weight: 400"> The CLI generates a warning when passing a password with </span><span style="font-weight: 400">-a</span><span style="font-weight: 400">, as it appears in bash history. For production systems, consider utilizing the </span><span style="font-weight: 400">VALKEYCLI_AUTH</span><span style="font-weight: 400"> environment variable instead. </span><i><span style="font-weight: 400">Note for Valkey 7.2.x users: As the first release following the Redis fork, the system still uses the legacy </span></i><i><span style="font-weight: 400">REDISCLI_AUTH</span></i><i><span style="font-weight: 400"> environment variable name.</span></i></p>
<pre class="urvanov-syntax-highlighter-plain-tag">valkey-cli -a YourSuperSecurePassword</pre>
<p><span style="font-weight: 400">Once inside the prompt, type the </span><span style="font-weight: 400">INFO replication</span><span style="font-weight: 400"> command:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">root@ArunValkeyPrimary:/home/ubuntu# valkey-cli -a&nbsp; amma@123

127.0.0.1:6379&gt; INFO replication
# Replication
role:master
connected_slaves:1
slave0:ip=172.31.37.55,port=6379,state=online,offset=126,lag=1
master_failover_state:no-failover
master_replid:7ef2ac2cc03b211c9571da0c0a53899327177349
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:126
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:126
127.0.0.1:6379&gt;</pre>
<p>Warning: Using a password with &lsquo;-a&rsquo; or &lsquo;-u&rsquo; option on the command line interface may not be safe.</p>
<p><b>Key Metrics to Watch:</b></p>
<ul>
<li><b>role</b><b>: Confirms this node is the master/primary.</b></li>
</ul>
<ul>
<li><b>state=online</b><b>: The replica is fully synced and streaming.</b></li>
</ul>
<ul>
<li><b>lag=0</b><b>: The replica is up to date. If this number climbs, the replica is struggling to keep up with the primary&rsquo;s write volume.</b></li>
</ul>
<ul>
<li><b>offset</b><b>: Matches the </b><b>master_repl_offset</b><b>, confirming data parity</b></li>
</ul>
<h3><b>The Write Test</b><a class="anchor-link" id="the-write-test"></a></h3>
<p><span style="font-weight: 400">To double-check the data flow, set a key on the primary:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag"># On Primary (172.31.32.27)
127.0.0.1:6379&gt; SET blog_status "Replication works!"
OK
127.0.0.1:6379&gt;</pre>
<p><span style="font-weight: 400">Then, hop over to the Replica&rsquo;s CLI and read the key:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag"># On Replica (172.31.37.55)
127.0.0.1:6379&gt; GET blog_status
"Replication works!"
127.0.0.1:6379&gt;</pre>

<h2><b>Wrapping Up</b><a class="anchor-link" id="wrapping-up"></a></h2>
<p><span style="font-weight: 400">With just a few configuration changes, you&rsquo;ve transformed a single-node Valkey setup into a scalable, production-ready replication topology. You now have data redundancy, improved read performance, and a solid foundation for growth.</span></p>
<p><span style="font-weight: 400">But there&rsquo;s one missing piece&mdash;automatic failover. If the primary node goes down, the replicas won&rsquo;t take over automatically. That&rsquo;s where the next evolution comes in.</span></p>
<p><span style="font-weight: 400">In the upcoming </span><a href="https://docs.google.com/document/d/1F_HtsNKi_-uf2Sma0WvHhFEreUlcIsJbC3ZRKeyOEEU/edit?usp=sharing"><span style="font-weight: 400">guide</span></a><span style="font-weight: 400">, (<b>Achieving High Availability with Valkey Sentinel) </b>I will dive into Valkey Sentinel and show how to turn this replicated setup into a fully self-healing, highly available system.</span></p>
<p>The post <a href="https://www.percona.com/blog/scaling-your-cache-a-step-by-step-guide-to-setting-up-valkey-replication/">Scaling Your Cache: A Step-by-Step Guide to Setting Up Valkey Replication</a> appeared first on <a href="https://www.percona.com">Percona</a>.</p>

<p>The post <a rel="nofollow" href="https://www.percona.com/blog/scaling-your-cache-a-step-by-step-guide-to-setting-up-valkey-replication/">Scaling Your Cache: A Step-by-Step Guide to Setting Up Valkey Replication</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Percona Live 2026 is Back in the Bay Area — Here’s Why You Don’t Want to Miss It</title>
      <link>https://www.percona.com/blog/percona-live-2026-is-back-in-the-bay-area-heres-why-you-dont-want-to-miss-it/</link>
      <pubDate>Wed, 22 Apr 2026 11:42:06 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://www.percona.com/blog/">Blog - Percona</source>
      <description><![CDATA[<p>We’re thrilled to welcome the open source database community back in person for Percona Live 2026, taking place May 27–29 in the Bay Area. After the energy of past events, there’s nothing like being together again — swapping war stories over coffee, sketching architectures on napkins, and learning from the people building and running databases … Continued<br />
The post Percona Live 2026 is Back in the Bay Area — Here’s Why You Don’t Want to Miss It appeared first on Percona.</p>
<p>The post <a rel="nofollow" href="https://www.percona.com/blog/percona-live-2026-is-back-in-the-bay-area-heres-why-you-dont-want-to-miss-it/">Percona Live 2026 is Back in the Bay Area — Here’s Why You Don’t Want to Miss It</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>We&rsquo;re thrilled to welcome the open source database community back in person for <strong>Percona Live 2026</strong>, taking place <strong>May 27&ndash;29 in the Bay Area</strong>. After the energy of past events, there&rsquo;s nothing like being together again &mdash; swapping war stories over coffee, sketching architectures on napkins, and learning from the people building and running databases at serious scale. The full schedule is live now, and it&rsquo;s shaping up to be our most hands-on, community-driven event yet.</p>
<p><strong>Save your seat</strong> &rarr;&nbsp; <a href="https://perconalive.com/2026-usa/registration/">Register for Percona Live 2026</a></p>
<h2>Keynotes You Won&rsquo;t Want to Miss<a class="anchor-link" id="keynotes-you-wont-want-to-miss"></a></h2>
<p>This year&rsquo;s keynote lineup reflects where the open source database world is heading &mdash; AI in the workflow, community ownership of the MySQL ecosystem, and extending the databases we already rely on. A few sessions we&rsquo;re especially excited about:</p>
<p><strong>Andy Pavlo, Carnegie Mellon University</strong> &mdash; &ldquo;<a href="https://perconalive.com/2026-usa/talks/using-llms-to-develop-and-optimize-database-systems/">Using LLMs to Develop and Optimize Database Systems</a>&rdquo; (Wednesday, opening keynote). Andy always brings sharp, evidence-based thinking, and this year he&rsquo;s digging into how large language models are genuinely changing how we build and tune database systems &mdash; separating real wins from the hype.</p>
<p><strong>Dominic Preuss, VillageSQL</strong> &mdash; &ldquo;<a href="https://perconalive.com/2026-usa/talks/driving-innovation-in-mysql-with-extensions/">Driving Innovation in MySQL with Extensions</a>&rdquo; (Thursday keynote). Dominic will share VillageSQL&rsquo;s vision for a more extensible MySQL, followed later in the day by his deep-dive breakout &ldquo;<a href="https://perconalive.com/2026-usa/talks/design-considerations-for-a-simple-extension-framework-for-mysql/">Design Considerations for a Simple Extension Framework for MySQL</a>&rdquo; &mdash; a great pairing if you care about the future of MySQL.</p>
<p><strong>Heather VanCura, Oracle</strong> &mdash; &ldquo;<a href="https://perconalive.com/2026-usa/talks/the-path-to-mysql-open-innovation/">The Path to MySQL Open Innovation</a>&rdquo; (Thursday keynote). Heather brings years of community-building experience to the stage, with a look at how open governance and community input are shaping MySQL&rsquo;s next chapter.</p>
<p><strong>Vadim Tkachenko, Percona</strong> &mdash; &ldquo;<a href="https://perconalive.com/2026-usa/talks/oursql-foundation-the-future-of-mysql-ecosystem/">OurSQL Foundation &mdash; The Future of the MySQL Ecosystem</a>&rdquo; (Wednesday keynote). Vadim will introduce the newly-formed OurSQL Foundation and what a truly community-led MySQL future can look like. If you care about where MySQL is going next, this one&rsquo;s essential.</p>
<p>And that&rsquo;s just a taste &mdash; we&rsquo;ve also got talks from engineers at Google, Meta, Pinterest, PayPal, Apple, Amazon, Plaid, and more across MySQL, PostgreSQL, MongoDB, Valkey, ClickHouse, and Kubernetes-native databases. The full lineup is on the <a href="https://perconalive.com/2026-usa/agenda/">agenda page</a>.</p>
<h2>Friday is Hands-On: Roll Up Your Sleeves<a class="anchor-link" id="friday-is-hands-on-roll-up-your-sleeves"></a></h2>
<p>New this year: we&rsquo;re making <strong>Friday, May 29 an all-day hands-on workshop day</strong>. These aren&rsquo;t lectures &mdash; they&rsquo;re real, practical deep-dives where you&rsquo;ll leave with working skills (and working configs). Bring your laptop.</p>
<ul>
<li><strong>Beyond apt install: Building Safe MySQL Test Environments</strong> with Sveta Smirnova (Percona)</li>
<li><strong>Build Real-Time Discovery and Recommendations with Valkey Search</strong> with Karthik Subbarao and Allen Samuels (Valkey)</li>
<li><strong>Building Highly Scalable PostgreSQL Platforms: Internals, Tuning, HA Automation</strong> with Avinash Vallarapu (HexaCluster)</li>
<li><strong>Hands-On PMM 3: Building a Professional Database Observability Stack</strong> with Michael Coburn and Tibor Korocz (Percona)</li>
<li><strong>MongoDB on Kubernetes 101: A Hands-On Guide</strong> with Michal Nosek (Percona)</li>
<li><strong>Migrating to MySQL High Availability with PXC</strong> with Matthew Boehm (Percona)</li>
<li><strong>Postgres DBA Accelerator</strong> with Alastair Turner (Percona) and Elizabeth Christensen (Snowflake)</li>
<li><strong>Cache Me If You Can, Valkey Edition</strong> with Roberto and Adrian Luna Rojas (Valkey)</li>
</ul>
<h2><b>Why Be There in Person</b><a class="anchor-link" id="why-be-there-in-person"></a></h2>
<p>The hallway conversations at Percona Live are honestly half the value. You&rsquo;ll meet the people behind the tools you run every day, compare notes with DBAs and engineers solving the same problems you are, and probably walk away with a few ideas you&rsquo;ll put into production next week. We&rsquo;re genuinely excited to be back together &mdash; and we&rsquo;d love to see you there.</p>
<p><strong>Ready to join us? <a href="https://perconalive.com/2026-usa/registration/">Register for Percona Live 2026</a></strong></p>
<p>The post <a href="https://www.percona.com/blog/percona-live-2026-is-back-in-the-bay-area-heres-why-you-dont-want-to-miss-it/">Percona Live 2026 is Back in the Bay Area &mdash; Here&rsquo;s Why You Don&rsquo;t Want to Miss It</a> appeared first on <a href="https://www.percona.com">Percona</a>.</p>

<p>The post <a rel="nofollow" href="https://www.percona.com/blog/percona-live-2026-is-back-in-the-bay-area-heres-why-you-dont-want-to-miss-it/">Percona Live 2026 is Back in the Bay Area — Here’s Why You Don’t Want to Miss It</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Impacts of updates in open-source databases</title>
      <link>https://www.percona.com/blog/impacts-of-updates-in-open-source-databases/</link>
      <pubDate>Tue, 21 Apr 2026 17:50:49 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://www.percona.com/blog/">Blog - Percona</source>
      <description><![CDATA[<p>We recently looked at how various open-source database engines maintain their secondary indexes (in a previous analysis) and found significant differences.  The maintenance of indexes is not the only aspect where storage engines differ, another significant difference is how they handle simple row updates.  These updates highlight how these open-source databases organize data and manage … Continued<br />
The post Impacts of updates in open-source databases appeared first on Percona.</p>
<p>The post <a rel="nofollow" href="https://www.percona.com/blog/impacts-of-updates-in-open-source-databases/">Impacts of updates in open-source databases</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>We recently looked at how various open-source database engines maintain their secondary indexes (<a href="https://www.percona.com/blog/osdb-index-maintenance/">in a previous analysis</a>) and found significant differences.&nbsp; The maintenance of indexes is not the only aspect where storage engines differ, another significant difference is how they handle simple row updates.&nbsp; These updates highlight how these open-source databases organize data and manage the&nbsp;versions of records while processing transactions. The management of versions is called MVCC, which stands for Multi-version Concurrency Control. In this post, we&rsquo;ll examine one aspect of open-source database engines: how IO-efficient they are for simple updates.</p>
<p>While performing updates, storage engines require access to storage for multiple reasons. Obviously, in order to update a record, it must be read from storage and, eventually, it will need to be written back. The storage engines also have to manage the record versions which, depending on the MVCC implementation, may require additional IOPs.&nbsp; All storage engines also use operational journal to sequentially log their operation for recovery purpose. These journals are called redo or WAL and are normally only written to. Finally, there must be crash protections against partial writes which could cause data corruption. Such protections also normally only consist of writes.</p>
<p>For this post, we&rsquo;ll conduct an experiment using the dataset created during the <a href="https://www.percona.com/blog/the-quirks-of-index-maintenance-in-open-source-databases/">previous post</a> and update an unindexed column from 100k randomly chosen rows. In order to see the impacts of data reorganization, we&rsquo;ll run updates to the same set of rows a second time. In both cases, we&rsquo;ll examine the total number of required IOPs, limited to a size of 16KB.</p>
<h2>Generalities about MVCC<a class="anchor-link" id="generalities-about-mvcc"></a></h2>
<p>Since the MVCC implementations are less known, let&rsquo;s first examine what exactly their responsibilities are. MVCC is required only when there is significant concurrency for access and manipulation of data. At low concurrency, locking is simpler and often preferred. A good example of this is MySQL&rsquo;s MyISAM engine, where any attempt to write to a table results in a full table lock.&nbsp; At higher concurrency, many sessions have queries running simultaneously. MVCC manages the record versions and determines which version a given transaction can see and update.</p>
<p>IO-wise, the aspects of MVCC that concern us relate to the handling and storage of the record versions. These versions are organized into lists and sorted by age. From a base record, there are two possible approaches for these lists: from oldest to newest (O2N) or from newest to oldest (N2O). Most storage engines use the N2O approach, with PostgreSQL being a notable exception, using mostly an O2N approach. Let&rsquo;s discuss in more detail examples of these two implementations.</p>
<h3><b>PostgreSQL MVCC</b><a class="anchor-link" id="postgresql-mvcc"></a></h3>
<p>As mentioned above, PostgreSQL uses mostly an oldest to newest (O2N) approach. When a row is updated, the whole row is copied to a new position, and only the version pointer (CTID) is updated in the original row. The old version will eventually be removed by the vacuum process. In a sense, an update in PostgreSQL is essentially an INSERT followed by an eventual DELETE. When a row needs to be accessed without an index, the oldest version is accessed and then the versions are iterated until the version compatible with the current transaction number is found. This means heavily updated rows could have a long list of versions and be slower to access. At some point, though, the vacuum process will kick in and shrink the list, removing the irrelevant versions.</p>
<p>PostgreSQL uses physical positions of rows (CTID) as pointers for indexes. After an update to a non-indexed column, the original index record points to the oldest version. An additional index entry is added if the updated row have been written a new page. The PostgreSQL behavior with row versions is quite complex, it is likely there are aspects I don&rsquo;t fully grasp. If someone wants to experiment and dig further on this topic, I recommend the <a href="https://www.postgresql.org/docs/current/pageinspect.html">pageinspect</a> extension, it is really awesome. Eventually, IOPs will be needed during vacuum to remove the old versions.</p>
<p>For more information on this topic, the following <a href="https://www.interdb.jp/pg/pgsql05/index.html">link</a> is a good starting point on PostgreSQL MVCC implementation. We must also keep on our radar a project developing a new MVCC implementation called <a href="https://www.orioledb.com/">Orioledb</a> but so far, it has a low adoption rate.</p>
<h3><b>InnoDB MVCC</b><a class="anchor-link" id="innodb-mvcc"></a></h3>
<p>InnoDB is a fairly typical implementation of the newest-to-oldest (N2O) approach. For simplicity, we&rsquo;ll restrict ourselves to updates. When a transaction updates a row, the row diff (or delta) is copied to the undo space. Then, the row is edited, and as part of the process, the field DB_ROLL_PTR is set to point to the undo position of the row diff. Finally, the field DB_TRX_ID is set to the ID of the transaction modifying the row.&nbsp; When another transaction attempts to read the same row, if its transaction ID is smaller than the recorded DB_TRX_ID, the DB_ROLL_PTR points to the previous version of the row.</p>
<p>When no running transaction needs an undo entry, the purge process removes it. That means for short transactions, the undo space lives in memory and is only persisted by the redo log. This removes a significant amount of IOPs. Also, the secondary indexes are not impacted because they use logical pointers, the primary key. For more information on InnoDB MVCC, see this excellent <a href="https://xialeistudio.medium.com/understanding-mvcc-in-mysql-innodb-116100a27b65">article</a>.</p>
<h2>Results<a class="anchor-link" id="results"></a></h2>
<p>The starting point of this experiment is the dataset at the end of our previous experiment, centered on the <a href="https://www.percona.com/blog/osdb-index-maintenance/">maintenance of secondary indexes</a>. These datasets have 10 million rows in a table with 7 indexes, one primary on an integer and 6 on large varchar UUID values. From that dataset, 100k rows were randomly selected for an update on the unindexed column, <i>status</i>.&nbsp; The updates were executed twice to illustrate the reorganization of data caused by the MVCC implementations.&nbsp; The best way to illustrate the impacts is to report the total number of IOPs (read and writes) to/from storage. For consistency, IOP sizes are limited to 16KB. The results are shown below:</p>
<figure id="attachment_43910" aria-describedby="caption-attachment-43910" style="width: 881px" class="wp-caption aligncenter"><img decoding="async" loading="lazy" class="size-full wp-image-43910" src="https://www.percona.com/wp-content/uploads/2026/04/dbbench-mvcc-updates-iops.png" alt="" width="881" height="497"><figcaption id="caption-attachment-43910" class="wp-caption-text">Total number of IOPs required to perform 100k updates</figcaption></figure>
<p>It is important to note the <b>logarithmic scale</b> used for Total IOPs. The large variation in IOPs imposed that choice of scale for readability.</p>
<h3><b>PostgreSQL</b><a class="anchor-link" id="postgresql"></a></h3>
<p>The &ldquo;Run 1&rdquo; of PostgreSQL illustrates the issues with its MVCC implementation. It is actually worse than I expected. This first set of updates required, on average, nearly 22 IOPs per update. A significant amount of these IOPs are caused by Full Page Writes (FPW). FPW occurs the first time a page is modified after a checkpoint. It is there to protect against torn pages, serving the same purpose as the InnoDB doublewrite buffer with MySQL.</p>
<p>Since PostgreSQL MVCC copies updated rows to new pages (which are append-only), this has the benefit of grouping the active rows. In our experiment, the updated rows, about 1% of all the rows, end up grouped together in a limited number of database pages. Because of this, the &ldquo;Run 2&rdquo; required less than 1/10th of the IOPs of &ldquo;Run 1&rdquo;. It is important to highlight the importance of this behavior as nearly all database workloads present a small subset of very active rows. While PostgreSQL old MVCC implementation bears a very high cost for the initial run, it kind of self-tunes for a much better &ldquo;Run 2&rdquo;.</p>
<h3><b>InnoDB</b><a class="anchor-link" id="innodb"></a></h3>
<p>InnoDB results are better in terms of IOPs and feature-less, both runs are within a few hundred IOPs of each other. This is a testimony to its younger MVCC design. The actual number of IOPs required is just a few percent above the second run of PostgreSQL. This means, while its behavior is excellent, performance will not improve over time with a small set of active rows.</p>
<h3><b>MongoDB</b><a class="anchor-link" id="mongodb"></a></h3>
<p>MongoDB WiredTiger engine required about 33% more IOPs than InnoDB in our experiment. Because of the way MongoDB evaluates updates, the actual value of the <i>status </i>had to be modified between the update runs, otherwise the second update would have been a no-op. The second run required about 8% less IOPs than the first one.</p>
<h3><b>MyRocks</b><a class="anchor-link" id="myrocks"></a></h3>
<p>RocksDB is optimized for writes, and it shows. MyRocks demonstrates a significant advantage over other engines. It required about 1/3rd of the IOPs of the second contender (InnoDB) for &ldquo;Run 1&rdquo; and, amazingly, only 1/30th of PostgreSQL (2nd best) for &ldquo;Run 2&rdquo;. Clearly, if your workload is dominated by writes, and you can cope with slightly slower reads, you should take a look at MyRocks.</p>
<h2>Conclusion<a class="anchor-link" id="conclusion"></a></h2>
<p>This database experiment sheds some light on the various Multi-version concurrency control implementations of popular database engines. We have observed large variations in the number of required IOPs between engines for similar workloads.</p>
<p>Here are some key points to remember:</p>
<ul>
<li>PostgreSQL MVCC implementation is the most inefficient in terms of IOPs</li>
<li>PostgreSQL efficiency improves considerably for &ldquo;Run 2&rdquo;.</li>
<li>PostgreSQL groups active rows together, improving efficiency.</li>
<li>InnoDB is a bit more efficient than MongoDB, but both are stable between runs</li>
<li>Given this is a write-only benchmark, MyRocks efficiency is in a different league as it plays to its strength</li>
<li>MyRocks is the clear winner, especially for the 2nd run, at more than an order of magnitude better than any other engine</li>
<li>MyRocks also groups active rows together, improving efficiency</li>
</ul>
<p>The post <a href="https://www.percona.com/blog/impacts-of-updates-in-open-source-databases/">Impacts of updates in open-source databases</a> appeared first on <a href="https://www.percona.com">Percona</a>.</p>

<p>The post <a rel="nofollow" href="https://www.percona.com/blog/impacts-of-updates-in-open-source-databases/">Impacts of updates in open-source databases</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Expanding board of directors – Kurt Daniel, CEO at Virtuozzo</title>
      <link>https://mariadb.org/expanding-board-of-directors-kurt-daniel-ceo-at-virtuozzo/</link>
      <pubDate>Tue, 21 Apr 2026 13:50:45 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.org/">MariaDB.org</source>
      <description><![CDATA[<p>The MariaDB Foundation is pleased to welcome Kurt Daniel, five-time CEO and current CEO of Virtuozzo, to its Board—bringing in a perspective shaped at the very heart of the database industry. …<br />
Continue reading \"Expanding board of directors – Kurt Daniel, CEO at Virtuozzo\"<br />
The post Expanding board of directors – Kurt Daniel, CEO at Virtuozzo appeared first on MariaDB.org.</p>
<p>The post <a rel="nofollow" href="https://mariadb.org/expanding-board-of-directors-kurt-daniel-ceo-at-virtuozzo/">Expanding board of directors – Kurt Daniel, CEO at Virtuozzo</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>The MariaDB Foundation is pleased to welcome <a href="https://www.linkedin.com/in/kurtdaniel/">Kurt Daniel</a>, five-time CEO and current CEO of <a href="https://www.virtuozzo.com/">Virtuozzo</a>, to its Board&mdash;bringing in a perspective shaped at the very heart of the database industry. &hellip; </p>
<p class="link-more"><a href="https://mariadb.org/expanding-board-of-directors-kurt-daniel-ceo-at-virtuozzo/" class="more-link">Continue reading<span class="screen-reader-text"> &ldquo;Expanding board of directors &ndash; Kurt Daniel, CEO at Virtuozzo&rdquo;</span></a></p>
<p>The post <a rel="nofollow" href="https://mariadb.org/expanding-board-of-directors-kurt-daniel-ceo-at-virtuozzo/">Expanding board of directors &ndash; Kurt Daniel, CEO at Virtuozzo</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>

<p>The post <a rel="nofollow" href="https://mariadb.org/expanding-board-of-directors-kurt-daniel-ceo-at-virtuozzo/">Expanding board of directors – Kurt Daniel, CEO at Virtuozzo</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Percona Operator for MySQL 1.1.0: PITR, Incremental Backups, and Compression</title>
      <link>https://www.percona.com/blog/percona-operator-for-mysql-1-1-0-pitr-incremental-backups-compression/</link>
      <pubDate>Tue, 21 Apr 2026 13:21:35 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://www.percona.com/blog/">Blog - Percona</source>
      <description><![CDATA[<p>The latest release of the Percona Operator for MySQL, 1.1.0, is here. It brings point-in-time recovery, incremental backups, zstd backup compression, configurable asynchronous replication retries, and a set of stability fixes. This post walks through the highlights and how they help your MySQL deployments on Kubernetes.   Percona Operator for MySQL 1.1.0 Running stateful databases … Continued<br />
The post Percona Operator for MySQL 1.1.0: PITR, Incremental Backups, and Compression appeared first on Percona.</p>
<p>The post <a rel="nofollow" href="https://www.percona.com/blog/percona-operator-for-mysql-1-1-0-pitr-incremental-backups-compression/">Percona Operator for MySQL 1.1.0: PITR, Incremental Backups, and Compression</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p><span style="font-weight: 400">The latest release of the <a href="https://docs.percona.com/percona-operator-for-mysql/ps/index.html">Percona Operator for MySQL</a>, <a href="https://docs.percona.com/percona-operator-for-mysql/ps/ReleaseNotes/Kubernetes-Operator-for-PS-RN1.1.0.html">1.1.0</a></span><span style="font-weight: 400">, is here. It brings </span><b>point-in-time recovery</b><span style="font-weight: 400">, </span><b>incremental backups</b><span style="font-weight: 400">, </span><b>zstd backup compression</b><span style="font-weight: 400">, configurable asynchronous replication retries, and a set of stability fixes. This post walks through the highlights and how they help your MySQL deployments on Kubernetes.</span></p>
<p>&nbsp;</p>
<h2><strong>Percona Operator for MySQL 1.1.0</strong><a class="anchor-link" id="percona-operator-for-mysql-1-1-0"></a></h2>
<p><img decoding="async" loading="lazy" class="aligncenter wp-image-43825 size-large" src="https://www.percona.com/wp-content/uploads/2026/04/hero-1024x375.png" alt="" width="1024" height="375"></p>
<p><span style="font-weight: 400">Running stateful databases on Kubernetes means your backup and recovery story has to be airtight. A full nightly backup is fine, until the DBA drops a table at 2 PM and you&rsquo;re looking at 14 hours of lost work. Or until your storage bill grows faster than your actual data because every backup is a full copy.</span></p>
<p><strong>Percona Operator for MySQL 1.1.0</strong> addresses exactly these pain points. This release lands&nbsp;<strong>point-in-time recovery</strong>,&nbsp;<strong>incremental backups</strong>, and&nbsp;<strong>backup compression</strong>: three features that together give you finer recovery control, faster backup jobs, and meaningfully smaller storage footprints. It also brings configurable asynchronous replication retries and a set of stability fixes that harden everyday operations.</p>
<p>This is a&nbsp;<strong>community-driven release</strong>. Nearly every headline feature in 1.1.0 traces back to user feedback: issues raised on&nbsp;<a href="https://forums.percona.com/" rel="nofollow">forums.percona.com</a>, JIRA tickets filed by operators in production, and recurring questions from teams running <strong>MySQL</strong> on <strong>Kubernetes</strong> at scale. The operator is fully open source, runs on any <strong>CNCF-conformant</strong> Kubernetes distribution (<strong>GKE, EKS, OpenShift, or bare metal</strong>), and costs nothing to run. Let&rsquo;s walk through what&rsquo;s new.</p>
<p>In this post, you&rsquo;ll learn about:</p>
<ul>
<li><strong>Point-in-Time Recovery</strong> (Tech Preview)</li>
<li><strong>Incremental Backups</strong> (Tech Preview)</li>
<li><strong>Backup Compression</strong> with zstd</li>
<li>Asynchronous replication retry configuration</li>
<li>Other improvements</li>
</ul>
<h2><span style="font-weight: 400"><br>
Point-in-Time Recovery (Tech Preview)</span><a class="anchor-link" id="point-in-time-recovery-tech-preview"></a></h2>
<h2><img decoding="async" loading="lazy" class="aligncenter wp-image-43827 size-large" src="https://www.percona.com/wp-content/uploads/2026/04/pitr-1024x342.png" alt="" width="1024" height="342"><a class="anchor-link" id=""></a></h2>
<p><span style="font-weight: 400">A backup restores your cluster to the moment the backup was taken, but incidents rarely respect your backup schedule. With </span><a href="https://docs.percona.com/percona-operator-for-mysql/ps/backups-pitr.html"><b>point-in-time recovery</b></a><span style="font-weight: 400"> now available in Tech Preview</span><span style="font-weight: 400">, you can restore your MySQL cluster to any specific timestamp or GTID position, not just to a backup snapshot.</span></p>
<p><span style="font-weight: 400">The operator continuously collects binary logs and stores them alongside your full and incremental backups. When a restore is needed, it starts from the nearest full backup, applies incremental backups, and then replays binary logs forward to the exact point in time you specify. <strong>PITR</strong> works identically across <strong>asynchronous</strong> and <strong>group replication</strong> topologies, so you don&rsquo;t need to restructure your setup to take advantage of it.</span></p>
<p><span style="font-weight: 400">A timestamp-based restore targets the exact moment before an incident:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">apiVersion: ps.percona.com/v1
kind: PerconaServerMySQLRestore
metadata:
  name: restore-pitr-example
spec:
  clusterName: cluster1
  backupName: backup-20260418
  pitr:
    type: date
    date: "2026-04-18 13:45:00"
    #Restore with GTID
#    type: gtid
#    gtid: a3e5ff70-83e2-11ef-8e57-7a62caf7e1e3:1-36</pre>
<p><span style="font-weight: 400">When you need finer precision than timestamp-based recovery (for example, replaying right up to the transaction immediately before a bad </span><i><span style="font-weight: 400">UPDATE</span></i><span style="font-weight: 400">), use </span><i><span style="font-weight: 400">pitr.type: gtid</span></i><span style="font-weight: 400"> and specify the exact GTID position.</span></p>
<p><span style="font-weight: 400">This is especially useful after an accidental </span><i><span style="font-weight: 400">DROP TABLE</span></i><span style="font-weight: 400"> or a bad application deploy mid-day: you recover to the moment just before the event, not to last night&rsquo;s snapshot.</span></p>
<p><span style="font-weight: 400">See the </span><a href="https://docs.percona.com/percona-operator-for-mysql/ps/backups-pitr.html"><span style="font-weight: 400">documentation</span></a><span style="font-weight: 400"> for the full configuration reference.</span></p>
<blockquote>
<p><em><span style="font-weight: 400"><strong>Note</strong>: PITR is marked </span><b>Tech Preview</b><span style="font-weight: 400"> in 1.1.0 and is <strong>not recommended</strong> for production workloads yet. Try it in staging and share your feedback on the community forum.</span></em></p>
<p>&nbsp;</p>
</blockquote>
<h2><span style="font-weight: 400">Incremental Backups (Tech Preview)</span><a class="anchor-link" id="incremental-backups-tech-preview"></a></h2>
<p><img decoding="async" loading="lazy" class="aligncenter wp-image-43828 size-large" src="https://www.percona.com/wp-content/uploads/2026/04/incremental-1024x256.png" alt="" width="1024" height="256"></p>
<p><span style="font-weight: 400">Full backups work, but they come with a cost: every job copies your entire dataset, consuming time, I/O, and storage whether or not much has changed since the last run. </span><b>Incremental backups</b> <span style="font-weight: 400">solve this by capturing only the changes since the previous backup.</span></p>
<p><span style="font-weight: 400">The Operator integrates incremental backup support, powered by </span><a href="https://docs.percona.com/percona-xtrabackup/8.4/"><span style="font-weight: 400">Percona XtraBackup</span></a><span style="font-weight: 400">, across all supported backup storage backends (<strong>S3-compatible, GCS, Azure Blob Storage)</strong>. Both <strong>scheduled</strong> and <strong>on-demand</strong> backup jobs can run incrementally. When you trigger a restore, the Operator reconstructs the full state by chaining the base backup with the subsequent incremental sets, so you don&rsquo;t manage that complexity manually.</span></p>
<p><span style="font-weight: 400">This helps when you need:</span></p>
<ul>
<li style="list-style-type: none">
<ul>
<li><span style="font-weight: 400">Faster daily backup jobs on large datasets that change slowly</span></li>
</ul>
</li>
</ul>
<ul>
<li style="list-style-type: none">
<ul>
<li><span style="font-weight: 400">Lower storage and egress costs per backup cycle</span></li>
</ul>
</li>
</ul>
<ul>
<li style="list-style-type: none">
<ul>
<li><span style="font-weight: 400">Tighter recovery windows without sacrificing backup frequency</span></li>
</ul>
</li>
</ul>
<ul>
<li style="list-style-type: none">
<ul>
<li><span style="font-weight: 400">Less I/O pressure on the primary during backup jobs</span></li>
</ul>
</li>
</ul>
<p><span style="font-weight: 400">The backup manifest lives in </span><a href="https://github.com/percona/percona-server-mysql-operator/blob/v1.1.0/deploy/backup/backup.yaml"><span style="font-weight: 400">deploy/backup/backup.yaml</span></a><span style="font-weight: 400">. Note the commented </span><i><span style="font-weight: 400">type</span></i><span style="font-weight: 400"> and </span><i><span style="font-weight: 400">incrementalBaseBackupName</span></i><span style="font-weight: 400"> fields: they are exactly how you switch a backup to incremental mode and point it at a previous backup as its base.</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">apiVersion: ps.percona.com/v1
kind: PerconaServerMySQLBackup
metadata:
  finalizers:
    - percona.com/delete-backup
  name: backup1
spec:
  clusterName: ps-cluster1
  storageName: minio
  type: incremental</pre>
<p><span style="font-weight: 400">Set <em>type: full</em> to take a base backup, then for each subsequent incremental set <em>type: incremental.</em></span></p>
<blockquote>
<p><em><span style="font-weight: 400"><strong>Note</strong>: Incremental backups are also marked </span><b>Tech Preview</b><span style="font-weight: 400"> in 1.1.0. You can learn more about this feature in a separate blog post: <a href="https://percona.community/blog/2026/04/17/incremental-backups-in-percona-kubernetes-operator-for-mysql/">Incremental backups in Percona Kubernetes Operator for MySQL</a></span></em></p>
<p>&nbsp;</p>
</blockquote>
<h2><span style="font-weight: 400">Backup Compression with zstd</span><a class="anchor-link" id="backup-compression-with-zstd"></a></h2>
<p><img decoding="async" loading="lazy" class="aligncenter wp-image-43829 size-large" src="https://www.percona.com/wp-content/uploads/2026/04/compression-1024x256.png" alt="" width="1024" height="256"></p>
<p><span style="font-weight: 400">Even without incremental backups, you can now shrink your full backup size significantly. The operator adds support for </span><span style="font-weight: 400">zstd</span><span style="font-weight: 400"> compression</span><span style="font-weight: 400">, which compresses backup data with <strong>Percona XtraBackup</strong> before it streams to object storage.</span></p>
<p><span style="font-weight: 400">Smaller transfers mean faster uploads, lower egress costs, and less object storage consumption, especially relevant when your cluster is in a different region from your storage bucket. The operator handles decompression transparently during restore, so your recovery workflow stays the same.</span></p>
<p><span style="font-weight: 400">You can enable compression globally by configuring XtraBackup in </span><em><span style="font-weight: 400">mysql.configuration</span></em><span style="font-weight: 400"> on the Custom Resource:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">spec:
  mysql:
    configuration: |
      [xtrabackup]
      compress=zstd</pre>
<p><span style="font-weight: 400">Or enable it per on-demand backup via </span><i><span style="font-weight: 400">containerOptions</span></i><span style="font-weight: 400">:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">apiVersion: ps.percona.com/v1
kind: PerconaServerMySQLBackup
metadata:
  name: backup1-compressed
  finalizers:
    - percona.com/delete-backup
spec:
  clusterName: ps-cluster1
  storageName: s3-us-west
  containerOptions:
    args:
      xtrabackup:
        - "--compress"</pre>
<p><span style="font-weight: 400">Full details are in the </span><a href="https://docs.percona.com/percona-operator-for-mysql/ps/backups-compressed.html"><span style="font-weight: 400">compressed backups documentation</span></a><span style="font-weight: 400">. Percona XtraBackup&rsquo;s </span><a href="https://docs.percona.com/percona-xtrabackup/8.4/create-compressed-backup.html?h=compressed#zstandard-zstd"><span style="font-weight: 400">zstd compression reference</span></a><span style="font-weight: 400"> covers the algorithm-level tradeoffs if you want to tune further. One known limitation in 1.1.0: </span><span style="font-weight: 400">lz4</span><span style="font-weight: 400"> compression is not yet supported pending an upstream resolution.</span></p>
<p>&nbsp;</p>
<h2><span style="font-weight: 400">Asynchronous Replication Retry Configuration</span><a class="anchor-link" id="asynchronous-replication-retry-configuration"></a></h2>
<p><img decoding="async" loading="lazy" class="aligncenter wp-image-43830 size-large" src="https://www.percona.com/wp-content/uploads/2026/04/async-retry-1024x256.png" alt="" width="1024" height="256"></p>
<p><span style="font-weight: 400">In asynchronous replication topologies, transient network issues can stall replication threads on a <strong>MySQL</strong> Pod. Previously, reconnection behavior was fixed. Now </span><span style="font-weight: 400">you can tune it via the Custom Resource using two environment variables:</span></p>
<ul>
<li style="font-weight: 400"><span style="font-weight: 400">ASYNC_SOURCE_RETRY_COUNT</span><span style="font-weight: 400">: the number of reconnection attempts before the replica gives up</span></li>
<li style="font-weight: 400">ASYNC_SOURCE_CONNECT_RETRY: the delay in seconds between reconnection attempts</li>
</ul>
<pre class="urvanov-syntax-highlighter-plain-tag">spec:
  mysql:
    env:
      - name: ASYNC_SOURCE_RETRY_COUNT
        value: "10"
      - name: ASYNC_SOURCE_CONNECT_RETRY
        value: "30"</pre>
<p><span style="font-weight: 400">This is useful in environments with higher network latency or less reliable connectivity between zones. You can give the replica more time to recover without manual intervention.</span></p>
<p><span style="font-weight: 400">A related improvement (</span><a href="https://perconadev.atlassian.net/browse/K8SPS-69"><span style="font-weight: 400">K8SPS-69</span></a><span style="font-weight: 400">): the readiness probe now fails if replication threads stop on a <strong>MySQL</strong> Pod. This prevents Kubernetes from routing traffic to a replica that has quietly fallen behind, a common source of stale reads that were difficult to detect without custom monitoring.</span></p>
<p>&nbsp;</p>
<h2><span style="font-weight: 400">Other Improvements</span><a class="anchor-link" id="other-improvements"></a></h2>
<p><span style="font-weight: 400">Operational polish shipped alongside the headline features:</span></p>
<ul>
<li style="list-style-type: none">
<ul>
<li><b>Readiness probe catches stopped replication</b><span style="font-weight: 400"> (</span><a href="https://perconadev.atlassian.net/browse/K8SPS-69"><span style="font-weight: 400">K8SPS-69</span></a><span style="font-weight: 400">): the readiness probe now fails when replication threads stop, so Kubernetes stops routing traffic to replicas that have quietly fallen behind.</span></li>
</ul>
</li>
</ul>
<ul>
<li style="list-style-type: none">
<ul>
<li><b>Automatic PVC removal on async replication restore</b><span style="font-weight: 400"> (</span><a href="https://perconadev.atlassian.net/browse/K8SPS-215"><span style="font-weight: 400">K8SPS-215</span></a><span style="font-weight: 400">): old PVCs are cleaned up automatically when restoring in async replication mode, one less manual step after a restore.</span></li>
</ul>
</li>
</ul>
<ul>
<li style="list-style-type: none">
<ul>
<li><b>Scheduled backups paused on unhealthy clusters</b><span style="font-weight: 400"> (</span><a href="https://perconadev.atlassian.net/browse/K8SPS-435"><span style="font-weight: 400">K8SPS-435</span></a><span style="font-weight: 400">): backups no longer kick off against a degraded cluster, preventing partial or corrupted backup sets.</span></li>
</ul>
</li>
</ul>
<ul>
<li style="list-style-type: none">
<ul>
<li><b>PMM agent temp path</b><span style="font-weight: 400"> (</span><a href="https://perconadev.atlassian.net/browse/K8SPS-467"><span style="font-weight: 400">K8SPS-467</span></a><span style="font-weight: 400">): the </span><a href="https://docs.percona.com/percona-monitoring-and-management/"><span style="font-weight: 400">Percona Monitoring and Management</span></a><span style="font-weight: 400"> agent now defaults its temp path to </span><i><span style="font-weight: 400">/tmp/pmm</span></i><span style="font-weight: 400">, improving compatibility across platforms including OpenShift.</span></li>
</ul>
</li>
</ul>
<ul>
<li style="list-style-type: none">
<ul>
<li><b>Structured error handling</b><span style="font-weight: 400"> (</span><a href="https://perconadev.atlassian.net/browse/K8SPS-595"><span style="font-weight: 400">K8SPS-595</span></a><span style="font-weight: 400">): invalid storage configurations now surface as structured error messages instead of Operator panics.</span></li>
</ul>
</li>
</ul>
<ul>
<li style="list-style-type: none">
<ul>
<li><b>Status events reclassified</b><span style="font-weight: 400"> (</span><a href="https://perconadev.atlassian.net/browse/K8SPS-601"><span style="font-weight: 400">K8SPS-601</span></a><span style="font-weight: 400">): normal status transitions emit as </span><i><span style="font-weight: 400">Normal</span></i><span style="font-weight: 400"> event types instead of warnings, cutting noise in </span><i><span style="font-weight: 400">kubectl describe</span></i><span style="font-weight: 400"> output and alerting pipelines.</span></li>
</ul>
</li>
</ul>
<ul>
<li style="list-style-type: none">
<ul>
<li><b>HAProxy file descriptor handling</b><span style="font-weight: 400"> (</span><a href="https://perconadev.atlassian.net/browse/K8SPS-666"><span style="font-weight: 400">K8SPS-666</span></a><span style="font-weight: 400">): file descriptor management in the HAProxy container is optimized so connection counts are no longer silently capped on busy clusters.</span></li>
</ul>
</li>
</ul>
<p><span style="font-weight: 400">The release also ships improved documentation: <strong>OpenShift</strong> installation instructions now include the full <strong>OLM</strong> procedure, an Operator upgrade tutorial for <strong>OpenShift</strong> has been added, and <strong>Helm</strong> documentation covers customized parameters and custom release naming.</span></p>
<p>&nbsp;</p>
<h2><span style="font-weight: 400">Conclusion</span><a class="anchor-link" id="conclusion"></a></h2>
<p><span style="font-weight: 400"><strong>Percona Operator for MySQL 1.1.0</strong> delivers meaningful improvements to every phase of the database lifecycle on Kubernetes. <strong>PITR</strong> and <strong>incremental</strong> backups in <strong>Tech Preview</strong> give you a path toward granular recovery without <strong>full-backup</strong> overhead. <strong>Compression</strong> with <strong>zstd</strong> reduces your storage and egress costs immediately. Configurable async replication retries and a batch of stability fixes harden the Operator for production workloads at scale. These features are in this release because the community asked for them.</span></p>
<p><span style="font-weight: 400">We encourage you to read the </span><a href="https://docs.percona.com/percona-operator-for-mysql/ps/ReleaseNotes/Kubernetes-Operator-for-PS-RN1.1.0.html"><span style="font-weight: 400">full release notes</span></a><span style="font-weight: 400"> and try the new features. Feedback is welcome on the </span><a href="https://github.com/percona/percona-server-mysql-operator/issues"><span style="font-weight: 400">GitHub repository</span></a><span style="font-weight: 400">, the </span><a href="https://forums.percona.com"><span style="font-weight: 400">Community Forum</span></a><span style="font-weight: 400">, or </span><a href="https://jira.percona.com/projects/K8SPS"><span style="font-weight: 400">JIRA</span></a><span style="font-weight: 400">.</span></p>
<p>&nbsp;</p>
<h2><span style="font-weight: 400">Try It Out</span><a class="anchor-link" id="try-it-out"></a></h2>
<ul>
<li style="font-weight: 400"><b>Release notes</b><span style="font-weight: 400">: </span><a href="https://docs.percona.com/percona-operator-for-mysql/ps/ReleaseNotes/Kubernetes-Operator-for-PS-RN1.1.0.html"><span style="font-weight: 400">Percona Operator for MySQL 1.1.0 Release Notes</span></a></li>
<li style="font-weight: 400"><b>GitHub</b><span style="font-weight: 400">: </span><a href="https://github.com/percona/percona-server-mysql-operator"><span style="font-weight: 400">percona/percona-server-mysql-operator</span></a></li>
<li style="font-weight: 400"><b>Community Forum</b>: <a href="https://forums.percona.com/c/mysql-mariadb/percona-kubernetes-operator-for-mysql/28">forums.percona.com</a>, share your feedback, ask questions, or report issues</li>
</ul>
<p>The post <a href="https://www.percona.com/blog/percona-operator-for-mysql-1-1-0-pitr-incremental-backups-compression/">Percona Operator for MySQL 1.1.0: PITR, Incremental Backups, and Compression</a> appeared first on <a href="https://www.percona.com">Percona</a>.</p>

<p>The post <a rel="nofollow" href="https://www.percona.com/blog/percona-operator-for-mysql-1-1-0-pitr-incremental-backups-compression/">Percona Operator for MySQL 1.1.0: PITR, Incremental Backups, and Compression</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>PostgreSQL Performance: Is Your Query Slow or Just Long-Running?</title>
      <link>https://www.percona.com/blog/postgresql-performance-is-your-query-slow-or-just-long-running/</link>
      <pubDate>Tue, 21 Apr 2026 06:43:22 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://www.percona.com/blog/">Blog - Percona</source>
      <description><![CDATA[<p>Introduction: Recently I was having a conversation with a DB Enthusiast, and he mentioned that when he was a fresher, he tuned an ETL/reporting query that was running for 8-10 hours via a nightly job by 1/3rd. He went to his manager, saying that he reduced the query execution time, thinking that the manager would … Continued<br />
The post PostgreSQL Performance: Is Your Query Slow or Just Long-Running? appeared first on Percona.</p>
<p>The post <a rel="nofollow" href="https://www.percona.com/blog/postgresql-performance-is-your-query-slow-or-just-long-running/">PostgreSQL Performance: Is Your Query Slow or Just Long-Running?</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<h3><span style="font-weight: 400">Introduction:</span><a class="anchor-link" id="introduction"></a></h3>
<p><span style="font-weight: 400">Recently I was having a conversation with a DB Enthusiast, and he mentioned that when he was a fresher, he tuned an ETL/reporting query that was running for 8-10 hours via a nightly job by 1/3rd. He went to his manager, saying that he reduced the query execution time, thinking that the manager would be happy. However, the manager said what business impact it is making. What difference will it make if this report is emailed to the boss at 2 AM instead of 8 AM. Eventually, he understood that he tuned the query that was actually not needed, and all the efforts were in vain</span><span style="font-weight: 400"> wasted.</span></p>
<p>&nbsp;</p>
<p><span style="font-weight: 400">If we put unnecessary indexes in any table that is doing more DMLs operations (INSERT, UPDATE or DELETE) that table will perform badly automatically. Business knows better than DBA whether the table will do more of DML or SELECTS and depending upon that tuning can be done. Of course DBA can check a few things with pg_stat_statements but the DBAs can not tell whether speeding up transactions or speeding up of a SELECT statement improves the business value.</span></p>
<p>&nbsp;</p>
<p><span style="font-weight: 400">For some applications like Analytics systems, ETL queries are bound to take more time and for some applications like foreign exchange platforms even the query taking a few milliseconds requires tuning. The lesson learnt is whether the query is slow or not, that business will tell. Business is the correct entity to identify whether they want to tune any query or not.&nbsp;</span></p>
<p><span style="font-weight: 400">The terms </span><i><span style="font-weight: 400">slow query</span></i><span style="font-weight: 400"> and </span><i><span style="font-weight: 400">long-running query</span></i><span style="font-weight: 400"> are often used interchangeably.</span></p>
<p><span style="font-weight: 400">They shouldn&rsquo;t be.</span></p>
<p><span style="font-weight: 400">Understanding the difference is critical because the tuning strategy for each is completely different.</span></p>
<p><span style="font-weight: 400">Let&rsquo;s break it down.</span></p>
<p>&nbsp;</p>
<h3><span style="font-weight: 400">What is a Slow Query?</span><a class="anchor-link" id="what-is-a-slow-query"></a></h3>
<p><span style="font-weight: 400">A </span><b>slow query</b><span style="font-weight: 400"> is a query that takes longer than expected due to inefficiencies and hence it multiplies infrastructure cost unnecessarily.</span></p>
<p><span style="font-weight: 400">This usually means below and more:</span></p>
<ul>
<li style="font-weight: 400"><span style="font-weight: 400">Incorrect/bad schema design</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Missing indexes</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Poor execution plan</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Sequential scans on large tables</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Incorrect join strategy</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Bad statistics</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Parameter mismatch and more</span></li>
</ul>
<p><span style="font-weight: 400">Example:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">SELECT *
FROM &nbsp; orders
WHERE&nbsp; customer_id = 10001;</pre>
<p><span style="font-weight: 400">If there&rsquo;s no index on </span><span style="font-weight: 400">customer_id</span><span style="font-weight: 400">, PostgreSQL will perform a </span><b>sequential scan</b><span style="font-weight: 400"> on the entire table.</span></p>
<p><span style="font-weight: 400">Even if it runs for only 5 seconds, it is slow because it </span><i><span style="font-weight: 400">could have run in milliseconds/nanoseconds </span></i><span style="font-weight: 400">with proper indexing.&nbsp;</span></p>
<p><span style="font-weight: 400">A slow query uses resources inefficiently.</span></p>
<p><span style="font-weight: 400">Again, make sure that tuning is actually needed by confirming with the business. If this query is used for a database that stores historical data, where more INSERTs occur than SELECTs</span><span style="font-weight: 400">,</span><span style="font-weight: 400"> then this index is not needed</span><span style="font-weight: 400">,</span><span style="font-weight: 400"> provided </span><span style="font-weight: 400">the</span><span style="font-weight: 400"> business confirms they want to tune this query.</span></p>
<h3><span style="font-weight: 400">What is a Long-Running Query?</span><a class="anchor-link" id="what-is-a-long-running-query"></a></h3>
<p><span style="font-weight: 400">A </span><b>long-running query</b><span style="font-weight: 400"> runs for a long time &mdash; but not necessarily inefficiently.</span></p>
<p><span style="font-weight: 400">These queries may:</span></p>
<ul>
<li style="font-weight: 400"><span style="font-weight: 400">Process millions/billions of rows</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Run complex aggregations</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Perform batch updates</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Execute reporting jobs</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Perform ETL workloads</span></li>
</ul>
<p><span style="font-weight: 400">Example:</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">INSERT INTO sales_summary 
SELECT date_trunc(&lsquo;month&rsquo;, sale_date), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
       SUM(amount) 
FROM &nbsp;sales 
WHERE sale_date &gt;= CURRENT_DATE - INTERVAL '30 days' 
GROUP&nbsp; BY 1</pre>
<p><span style="font-weight: 400">If the </span><span style="font-weight: 400">sales</span><span style="font-weight: 400"> table has 500 million rows, this query may run for 15 minutes on the first day of every month &mdash; and that&rsquo;s perfectly fine.</span></p>
<p><span style="font-weight: 400">It&rsquo;s long-running, but not slow.</span></p>
<h3><span style="font-weight: 400">The Core Difference</span><a class="anchor-link" id="the-core-difference"></a></h3>
<table border="1">
<tbody>
<tr>
<td style="width: 129.953px"><b>Aspect</b></td>
<td style="width: 263.805px"><b>Slow Query</b></td>
<td style="width: 321.391px"><b>Long-Running Query</b></td>
</tr>
<tr>
<td style="width: 129.953px"><span style="font-weight: 400">Root cause</span></td>
<td style="width: 263.805px"><span style="font-weight: 400">Poor indexing, stale statistics, or bad SQL.</span></td>
<td style="width: 321.391px"><span style="font-weight: 400">Large data volume, complex joins, or heavy reports.</span></td>
</tr>
<tr>
<td style="width: 129.953px"><span style="font-weight: 400">Fix</span></td>
<td style="width: 263.805px"><span style="font-weight: 400">Query tuning</span></td>
<td style="width: 321.391px"><span style="font-weight: 400">Workload planning</span></td>
</tr>
<tr>
<td style="width: 129.953px"><span style="font-weight: 400">CPU usage</span></td>
<td style="width: 263.805px"><span style="font-weight: 400">Often high per row</span></td>
<td style="width: 321.391px"><span style="font-weight: 400">May be proportional</span></td>
</tr>
<tr>
<td style="width: 129.953px"><span style="font-weight: 400">Business justification</span></td>
<td style="width: 263.805px"><span style="font-weight: 400">Usually none</span></td>
<td style="width: 321.391px"><span style="font-weight: 400">Often valid</span></td>
</tr>
</tbody>
</table>
<p><span style="font-weight: 400">A slow query is a </span><b>performance problem</b><span style="font-weight: 400">.</span><span style="font-weight: 400"><br>
</span><span style="font-weight: 400">A long-running query is often a </span><b>capacity or workload problem</b><span style="font-weight: 400">.</span></p>
<h3><span style="font-weight: 400">The Dangerous Confusion</span><a class="anchor-link" id="the-dangerous-confusion"></a></h3>
<p><span style="font-weight: 400">The real issue occurs when:</span></p>
<ul>
<li style="font-weight: 400"><span style="font-weight: 400">A slow query becomes long-running</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">A long-running query blocks OLTP traffic</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">DBAs kill legitimate analytical queries</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Developers add unnecessary indexes</span></li>
</ul>
<p><span style="font-weight: 400">Not every 10-minute query is bad.</span><span style="font-weight: 400"><br>
</span><span style="font-weight: 400">Not every 2-second query is good.</span></p>
<p><span style="font-weight: 400">Context matters. Business justification matters more.</span></p>
<p>&nbsp;</p>
<h3><span style="font-weight: 400">When a Long-Running Query Becomes a Problem</span><a class="anchor-link" id="when-a-long-running-query-becomes-a-problem"></a></h3>
<p><span style="font-weight: 400">A long-running query becomes dangerous when it:</span></p>
<ul>
<li style="font-weight: 400"><span style="font-weight: 400">Holds locks</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Blocks vacuum</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Causes bloat</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Consumes excessive memory</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Saturates I/O</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Impacts replication lag</span></li>
</ul>
<p><span style="font-weight: 400">What can be done</span></p>
<h3><span style="font-weight: 400">If it&rsquo;s Slow:</span><a class="anchor-link" id="if-its-slow"></a></h3>
<ul>
<li style="font-weight: 400"><span style="font-weight: 400">Run </span><span style="font-weight: 400">EXPLAIN (ANALYZE, BUFFERS)</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Check index usage</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Check row estimates vs actual rows</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Review statistics</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Look for nested loop disasters</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Check for duplicate and unused indexes</span></li>
</ul>
<p><span style="font-weight: 400">Additionally, Tuning blogs like below can help in tuning</span></p>
<p><a href="https://www.percona.com/blog/tuning-postgresql-database-parameters-to-optimize-performance/"><span style="font-weight: 400">PostgreSQL Performance Tuning Guide: Settings That Make a Difference</span></a></p>
<p><a href="https://www.percona.com/blog/sql-optimizations-in-postgresql-in-vs-exists-vs-any-all-vs-join/"><span style="font-weight: 400">SQL Optimizations in PostgreSQL: IN vs EXISTS vs ANY/ALL vs JOI</span></a><span style="font-weight: 400">N</span></p>
<p>&nbsp;</p>
<h3><span style="font-weight: 400">If it&rsquo;s Long-Running:</span><a class="anchor-link" id="if-its-long-running"></a></h3>
<ul>
<li style="font-weight: 400"><span style="font-weight: 400">Move to batch window</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Use parallelism</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Increase work_mem carefully</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Consider partitioning</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Offload to reporting replica</span></li>
</ul>
<h3><span style="font-weight: 400">Conclusion:</span><a class="anchor-link" id="conclusion"></a></h3>
<p><em><span style="font-weight: 400">Every slow query is a problem.</span><span style="font-weight: 400"><br>
</span><span style="font-weight: 400">Not every long-running query is.</span></em></p>
<p><span style="font-weight: 400">Before killing a query in production, ask:</span></p>
<blockquote>
<p><span style="font-weight: 400">Is this inefficient &mdash; or is it just doing a lot of work?</span></p>
</blockquote>
<p><span style="font-weight: 400">That distinction defines whether it needs tuning or rescheduling.</span><span style="font-weight: 400">Business knows the answer better than a DBA in most cases.</span></p>
<p>The post <a href="https://www.percona.com/blog/postgresql-performance-is-your-query-slow-or-just-long-running/">PostgreSQL Performance: Is Your Query Slow or Just Long-Running?</a> appeared first on <a href="https://www.percona.com">Percona</a>.</p>

<p>The post <a rel="nofollow" href="https://www.percona.com/blog/postgresql-performance-is-your-query-slow-or-just-long-running/">PostgreSQL Performance: Is Your Query Slow or Just Long-Running?</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Deploying Cross-Site Replication in Percona Operator for MySQL (PXC)</title>
      <link>https://www.percona.com/blog/deploying-cross-site-replication-in-percona-operator-for-mysql-pxc/</link>
      <pubDate>Mon, 20 Apr 2026 13:15:04 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://www.percona.com/blog/">Blog - Percona</source>
      <description><![CDATA[<p>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 - > DR] topology for Percona XtraDB Cluster (PXC), which is a virtually- synchronous cluster, can be a bit challenging in a complex … Continued<br />
The post Deploying Cross-Site Replication in Percona Operator for MySQL (PXC) appeared first on Percona.</p>
<p>The post <a rel="nofollow" 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 rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p><span style="font-weight: 400">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 style="font-weight: 400">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 style="font-weight: 400">So without taking much time, let&rsquo;s see how the overall setup and configurations look from a practical standpoint.</span></p>
<p>&nbsp;</p>
<figure id="attachment_43844" aria-describedby="caption-attachment-43844" style="width: 960px" class="wp-caption alignnone"><img decoding="async" loading="lazy" 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"><figcaption id="caption-attachment-43844" class="wp-caption-text">PXC Cross-Site/Disaster Recovery</figcaption></figure>
<p>&nbsp;</p>
<h2>DC Configuration<a class="anchor-link" id="dc-configuration"></a></h2>
<p><span style="font-weight: 400"><span style="font-weight: 400">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 style="font-weight: 400">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 style="font-weight: 400"><span style="font-weight: 400">Expose all source PXC nodes so they can be communicated from outside or DR cluster.</span></li>
</ul>
<pre class="urvanov-syntax-highlighter-plain-tag">expose:
      	enabled: true
      	Type: LoadBalancer</pre>

<ul>
<li style="font-weight: 400"><span style="font-weight: 400">Define a dedicated replication channel and enable the source option.</span></li>
</ul>
<pre class="urvanov-syntax-highlighter-plain-tag">replicationChannels:
    - name: pxc1_to_pxc2
      isSource: true</pre>

<ul>
<li style="font-weight: 400"><span style="font-weight: 400">Finally, applying the custom resource changes.</span></li>
</ul>
<pre class="urvanov-syntax-highlighter-plain-tag">shell&gt; kubectl apply -f cr.yaml</pre>
<p><span style="font-weight: 400">3) Now we will notice some</span><b> &ldquo;EXTERNAL IP&rdquo;</b><span style="font-weight: 400"> 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 style="font-weight: 400">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>&nbsp;</p>
<h2><span style="font-weight: 400">Backup</span><a class="anchor-link" id="backup"></a></h2>
<ul>
<li style="font-weight: 400"><span style="font-weight: 400">Defining access key/secrets to connect to the GCP/S3 bucket.</span></li>
</ul>
<pre class="urvanov-syntax-highlighter-plain-tag">cat backup-secret-s3.yaml</pre>

<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>

<ul>
<li style="font-weight: 400"><span style="font-weight: 400">In the custom resource file [cr.yaml] , we also need to define the bucket , secret file and endpoint/region details.</span></li>
</ul>
<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>&hellip;</p>
<pre class="urvanov-syntax-highlighter-plain-tag">shell&gt; kubectl apply -f cr.yaml</pre>

<ul>
<li style="font-weight: 400"><span style="font-weight: 400">Finally, we can take the backup by creating a [</span><b>backup.yaml]</b><span style="font-weight: 400"> file with below details.</span></li>
</ul>
<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>&hellip;</p>
<pre class="urvanov-syntax-highlighter-plain-tag">shell&gt; kubectl apply -f cr.yaml</pre>

<ul>
<li style="font-weight: 400"><span style="font-weight: 400">We can verify the successful backup as follows.</span></li>
</ul>
<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 style="font-weight: 400">As the backup is also ready, we can now move to the DR setup part.</span></p>
<p>&nbsp;</p>
<h2><span style="font-weight: 400">DR Configuration</span><a class="anchor-link" id="dr-configuration"></a></h2>
<p><span style="font-weight: 400">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 style="font-weight: 400">First, we need to restore the backup on the DR server.</span></p>
<h2><a class="anchor-link" id=""></a></h2>
<h2><span style="font-weight: 400">Data Restoration</span><a class="anchor-link" id="data-restoration"></a></h2>
<ul>
<li style="font-weight: 400"><span style="font-weight: 400">Here we will create the [</span><b>backup-secret-s3.yaml</b><span style="font-weight: 400">] file which contains the GCP/S3 credentials.</span></li>
</ul>
<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>&hellip;</p>
<pre class="urvanov-syntax-highlighter-plain-tag">shell&gt; kubectl apply -f backup-secret-s3.yaml</pre>

<ul>
<li style="font-weight: 400"><span style="font-weight: 400">Next, we will create a [</span><b>restore.yaml</b><span style="font-weight: 400">] file while mentioning the backup source and other useful information.</span></li>
</ul>
<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>&hellip;</p>
<pre class="urvanov-syntax-highlighter-plain-tag">shell&gt; kubectl apply -f restore.yaml</pre>

<ul>
<li style="font-weight: 400"><span style="font-weight: 400">Once the restoration is finished successfully, we will see the status below.</span></li>
</ul>
<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 style="font-weight: 400">Now we can do the remaining DR changes in the custom resource file [</span><b>cr.yaml</b><span style="font-weight: 400">]. 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 style="font-weight: 400">Automatic Asynchronous Replication Connection Failover feature</span></a><span style="font-weight: 400">, 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>&hellip;</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>&nbsp;</p>
</blockquote>
<h2>Replication<a class="anchor-link" id="replication"></a></h2>
<p><span style="font-weight: 400">Initially, when we check the replication status, we can notice the following error. This is because with [</span><b>caching_sha2_password</b><span style="font-weight: 400">] 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 style="font-weight: 400">/</span><b>GET_SOURCE_PUBLIC_KEY</b></a><span style="font-weight: 400">&nbsp; which basicaly enables the RSA key pair-based password exchange by requesting the public key from the source.&nbsp;</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">shell&gt; kubectl exec -it cluster1-pxc-0  -- sh
shell&gt; mysql -uroot -p</pre>

<pre class="urvanov-syntax-highlighter-plain-tag">mysql&gt; show replica statusG;
*************************** 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>

<h5><b>Error:</b></h5>

<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 style="font-weight: 400">Once we passed &ldquo;</span><b>GET_SOURCE_PUBLIC_KEY&rdquo; </b><span style="font-weight: 400">in the</span><b> &ldquo;CHANGE REPLICATION&rdquo; </b><span style="font-weight: 400">command</span> <span style="font-weight: 400">the&nbsp; 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>

<h5><b>Note</b><span style="font-weight: 400">&nbsp; &ndash; 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 &ldquo;</span><b>replication</b><span style="font-weight: 400">&rdquo; user.</span></h5>

<pre class="urvanov-syntax-highlighter-plain-tag">shell&gt; kubectl get secret cluster1-secrets -o jsonpath="{.data.replication}" | base64 --decode</pre>

<pre class="urvanov-syntax-highlighter-plain-tag">mysql&gt; show replica statusG;
*************************** 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 style="font-weight: 400">The other PXC DR nodes will sync as usual with the Galera Synchronous replication process.&nbsp;</span></p>
<h2><a class="anchor-link" id=""></a></h2>
<h2><span style="font-weight: 400">Source Failover</span><a class="anchor-link" id="source-failover"></a></h2>
<p><span style="font-weight: 400">The asynchronous connection failover is already enabled on the DR as we defined initially in the custom resource file. The &ldquo;External IPs&rdquo;&nbsp; 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 style="font-weight: 400">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 &ldquo;Weight&rdquo; and chronological order [pxc-2, pxc-1, pxc-0 etc].</span></p>
<ul>
<li style="font-weight: 400"><span style="font-weight: 400">Here, we temporarily take down the Source DC[cluster1-pxc-2] node.</span></li>
</ul>
<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>

<ul>
<li style="font-weight: 400"><span style="font-weight: 400">The DR replication breaks as it can&rsquo;t reach the DC [cluster1-pxc-2].</span></li>
</ul>
<pre class="urvanov-syntax-highlighter-plain-tag">mysql&gt; show replica statusG;
*************************** 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>

<ul>
<li style="font-weight: 400"><span style="font-weight: 400">Once it reaches the &ldquo;</span><b>source_retry_count&rdquo;</b><span style="font-weight: 400"> and &ldquo;</span><b>source_connect_retry&rdquo;,</b><span style="font-weight: 400"> the Replica connects to another Source DC[cluster1-pxc-1].</span></li>
</ul>
<pre class="urvanov-syntax-highlighter-plain-tag">mysql&gt; show replica statusG;
*************************** 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>

<h2><a class="anchor-link" id=""></a></h2>
<h2><span style="font-weight: 400">Quick Summary</span><a class="anchor-link" id="quick-summary"></a></h2>
<p><span style="font-weight: 400">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.&nbsp;</span></p>
<p><span style="font-weight: 400">Using an &ldquo;Asynchronous Replication&rdquo; 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&rsquo;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>

<p>The post <a rel="nofollow" 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 rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Incremental backups in Percona Kubernetes Operator for MySQL</title>
      <link>https://percona.community/blog/2026/04/17/incremental-backups-in-percona-kubernetes-operator-for-mysql/</link>
      <pubDate>Fri, 17 Apr 2026 10:00:00 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://percona.community/blog/">Percona Community Blog - learn about MySQL, MariaDB, PostgreSQL, and MongoDB</source>
      <description><![CDATA[<p>Starting with version 1.1.0, the Percona Kubernetes Operator for MySQL now supports incremental backups. This feature lets you backup only the changed data since the last backup, instead of copying your entire dataset each time. The result is dramatically smaller backup sizes, faster backup windows, and lower cloud storage costs.</p>
<p>The post <a rel="nofollow" href="https://percona.community/blog/2026/04/17/incremental-backups-in-percona-kubernetes-operator-for-mysql/">Incremental backups in Percona Kubernetes Operator for MySQL</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>Starting with version 1.1.0, the Percona Kubernetes Operator for MySQL now supports <strong>incremental backups</strong>. This feature lets you backup only the changed data since the last backup, instead of copying your entire dataset each time. The result is dramatically smaller backup sizes, faster backup windows, and lower cloud storage costs.</p>
<p>In this post, we&rsquo;ll walk through how the feature works under the hood, how to configure it, and what to keep in mind when designing your backup strategy.</p>
<h2 id="how-incremental-backups-work-in-percona-xtrabackup">How Incremental Backups Work in Percona XtraBackup<a class="anchor-link" id="how-incremental-backups-work-in-percona-xtrabackup"></a></h2>
<p>The foundation of this feature is <a href="https://docs.percona.com/percona-xtrabackup/latest/" target="_blank" rel="noopener noreferrer">Percona XtraBackup (PXB)</a>, an open source backup tool for MySQL. PXB has supported incremental backups for a while, and the operator now brings that capability into the backup workflow.</p>
<p>Every InnoDB data page carries a <strong>Log Sequence Number (LSN)</strong>, which is a monotonically increasing counter that records when the page was last modified. When PXB takes an incremental backup, it scans data pages and copies only those with an LSN newer than a reference point. The output is a set of compact <code>.delta</code> files instead of full tablespace copies.</p>
<p>Each backup produces an <code>xtrabackup_checkpoints</code> file:</p>
<div class="code-block">
<div class="code-block__header"><button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-0">
<div class="highlight">
<pre class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">backup_type = full-backuped
</span></span><span class="line"><span class="cl">from_lsn = 0
</span></span><span class="line"><span class="cl">to_lsn = 7345291
</span></span><span class="line"><span class="cl">last_lsn = 7345291</span></span></code></pre>
</div>
</div>
</div>
<p>Each incremental&rsquo;s <code>from_lsn</code> must equal the previous backup&rsquo;s <code>to_lsn</code>.</p>
<h2 id="using-incremental-backups-with-the-operator">Using Incremental Backups with the Operator<a class="anchor-link" id="using-incremental-backups-with-the-operator"></a></h2>
<h3 id="on-demand-incremental-backup">On-Demand Incremental Backup<a class="anchor-link" id="on-demand-incremental-backup"></a></h3>
<p>First, you need a full backup to serve as the base:</p>
<div class="code-block">
<div class="code-block__header"><span class="code-block__lang">yaml</span><button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-1">
<div class="highlight">
<pre class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l">ps.percona.com/v1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">PerconaServerMySQLBackup</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">metadata</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">weekly-full</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">spec</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">clusterName</span><span class="p">:</span><span class="w"> </span><span class="l">my-cluster</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">storageName</span><span class="p">:</span><span class="w"> </span><span class="l">s3-us</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">full</span></span></span></code></pre>
</div>
</div>
</div>
<p>Once the full backup succeeds, create an incremental:</p>
<div class="code-block">
<div class="code-block__header"><span class="code-block__lang">yaml</span><button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-2">
<div class="highlight">
<pre class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l">ps.percona.com/v1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">PerconaServerMySQLBackup</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">metadata</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">daily-inc-1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">spec</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">clusterName</span><span class="p">:</span><span class="w"> </span><span class="l">my-cluster</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">storageName</span><span class="p">:</span><span class="w"> </span><span class="l">s3-us</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">incremental</span></span></span></code></pre>
</div>
</div>
</div>
<p>The operator automatically discovers the latest succeeded full backup for the same cluster and storage, fetches its LSN, and creates an incremental backup. If you want to pin a specific base, simply use the <code>incrementalBaseBackupName</code> field:</p>
<div class="code-block">
<div class="code-block__header"><span class="code-block__lang">yaml</span><button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-3">
<div class="highlight">
<pre class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">spec</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">incremental</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">incrementalBaseBackupName</span><span class="p">:</span><span class="w"> </span><span class="l">weekly-full</span></span></span></code></pre>
</div>
</div>
</div>
<h3 id="scheduled-backups-full--incremental">Scheduled Backups: Full + Incremental<a class="anchor-link" id="scheduled-backups-full-incremental"></a></h3>
<p>The real power comes from combining full and incremental schedules. Here&rsquo;s an example: weekly full backups with daily incrementals:</p>
<div class="code-block">
<div class="code-block__header"><span class="code-block__lang">yaml</span><button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-4">
<div class="highlight">
<pre class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">spec</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">backup</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">schedule</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">weekly-full</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">schedule</span><span class="p">:</span><span class="w"> </span><span class="s2">"0 0 * * 0"</span><span class="w"> </span><span class="c"># Sunday midnight</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">keep</span><span class="p">:</span><span class="w"> </span><span class="m">4</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">storageName</span><span class="p">:</span><span class="w"> </span><span class="l">s3-us</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">full</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">daily-incremental</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">schedule</span><span class="p">:</span><span class="w"> </span><span class="s2">"0 0 * * 1-6"</span><span class="w"> </span><span class="c"># Monday through Saturday</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">storageName</span><span class="p">:</span><span class="w"> </span><span class="l">s3-us</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">incremental</span></span></span></code></pre>
</div>
</div>
</div>
<p>The <code>keep</code> rotation policy is chain-aware: it counts only full backups and automatically cascade-deletes all dependent incrementals when a full backup is rotated out.</p>
<h3 id="restoring-from-an-incremental-backup">Restoring from an Incremental Backup<a class="anchor-link" id="restoring-from-an-incremental-backup"></a></h3>
<p>The <code>PerconaServerMySQLRestore</code> custom resource allows you to restore from any point in an incremental, similar to restoring a full backup:</p>
<div class="code-block">
<div class="code-block__header"><span class="code-block__lang">yaml</span><button class="code-block__copy" type="button" data-copy-target="codeblock-5" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-5">
<div class="highlight">
<pre class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l">ps.percona.com/v1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">PerconaServerMySQLRestore</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">metadata</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">restore-to-wednesday</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">spec</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">clusterName</span><span class="p">:</span><span class="w"> </span><span class="l">my-cluster</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">backupName</span><span class="p">:</span><span class="w"> </span><span class="l">daily-inc-3</span></span></span></code></pre>
</div>
</div>
</div>
<p>The operator handles the complexity behind the scenes:</p>
<ol>
<li>Discovers the full chain by listing the cloud storage directory</li>
<li>Downloads and prepares the base full backup</li>
<li>Applies each incremental in sequence</li>
<li>Applies the final incremental and rolls back uncommitted transactions</li>
<li>Moves the prepared data back to the MySQL data directory</li>
</ol>
<p>You don&rsquo;t need to know which backup is the base or how many incrementals are in the chain, the operator figures it out.</p>
<h2 id="how-it-works-under-the-hood">How It Works Under the Hood<a class="anchor-link" id="how-it-works-under-the-hood"></a></h2>
<h3 id="storage-layout">Storage Layout<a class="anchor-link" id="storage-layout"></a></h3>
<p>The operator uses a specific directory convention to encode backup chains without any requiring any additional metadata:</p>
<div class="code-block">
<div class="code-block__header"><button class="code-block__copy" type="button" data-copy-target="codeblock-6" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-6">
<div class="highlight">
<pre class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">s3://bucket/prefix/
</span></span><span class="line"><span class="cl"> my-cluster-2026-04-06-full/ # base full backup
</span></span><span class="line"><span class="cl"> my-cluster-2026-04-06-full.incr/ # incremental chain directory
</span></span><span class="line"><span class="cl"> my-cluster-2026-04-07T000000-incr/ # Monday's incremental
</span></span><span class="line"><span class="cl"> my-cluster-2026-04-08T000000-incr/ # Tuesday's incremental
</span></span><span class="line"><span class="cl"> my-cluster-2026-04-09T000000-incr/ # Wednesday's incremental</span></span></code></pre>
</div>
</div>
</div>
<p>The <code>.incr/</code> suffix creates a self-describing structure. Any cluster with access to the storage bucket can reconstruct the chain, making cross-cluster restores straightforward.</p>
<h3 id="the-backup-flow">The Backup Flow<a class="anchor-link" id="the-backup-flow"></a></h3>
<p>Here&rsquo;s what happens when you create an incremental backup:</p>
<ol>
<li><strong>Resolve the base.</strong> The controller finds the latest succeeded full backup (or the one you specified) and annotates the incremental CR with <code>percona.com/base-backup-name</code>.</li>
<li><strong>Fetch the LSN.</strong> The controller calls the xtrabackup sidecar&rsquo;s <code>/backup/checkpoint-info</code> endpoint. The sidecar downloads <code>xtrabackup_checkpoints</code> from the previous backup via <code>xbcloud get</code>, parses it, and returns the <code>to_lsn</code>.</li>
<li><strong>Launch the backup job.</strong> A Kubernetes Job is created with the <code>INCREMENTAL_LSN</code> environment variable set.</li>
<li><strong>Stream to storage.</strong> The sidecar runs <code>xtrabackup --backup --stream=xbstream --incremental-lsn=</code> and pipes the output through <code>xbcloud put</code> to the cloud destination.</li>
</ol>
<h3 id="chain-integrity-protection">Chain Integrity Protection<a class="anchor-link" id="chain-integrity-protection"></a></h3>
<p>The operator enforces chain integrity at multiple levels:</p>
<ul>
<li><strong>Deletion guards:</strong> Only the latest incremental in a chain can be deleted. Attempting to delete a mid-chain backup is blocked using finalizers.</li>
<li><strong>Cascade deletion:</strong> Deleting a full backup automatically removes all dependent incrementals, from newest to oldest.</li>
<li><strong>Concurrent backup prevention:</strong> The controller uses a Lease-based mechanism to prevent multiple incremental backups from running at the same time.</li>
</ul>
<h2 id="designing-your-backup-strategy">Designing Your Backup Strategy<a class="anchor-link" id="designing-your-backup-strategy"></a></h2>
<h3 id="when-to-use-incremental-backups">When to Use Incremental Backups<a class="anchor-link" id="when-to-use-incremental-backups"></a></h3>
<p>Incremental backups shine when:</p>
<ul>
<li><strong>Your database is large but change rate is low.</strong> A 1 TB database with 2% daily change produces ~20 GB incremental backups instead of 1 TB full backups.</li>
<li><strong>You need frequent backup points.</strong> Run hourly incrementals with minimal overhead.</li>
<li><strong>Cloud storage costs matter.</strong> Example: with about <strong>2%</strong> of the data changing each day, <strong>one full backup</strong> plus <strong>six daily incrementals</strong> needs roughly <strong>one-fifth</strong> the space of keeping <strong>six separate full backups</strong> over the same week.</li>
</ul>
<h3 id="what-to-keep-in-mind">What to Keep in Mind<a class="anchor-link" id="what-to-keep-in-mind"></a></h3>
<ul>
<li><strong>All chain members must use the same storage backend.</strong> You can&rsquo;t mix S3 and GCS within a chain.</li>
<li><strong>Chain integrity is critical.</strong> If a backup in the chain is corrupted, all subsequent incrementals in that chain become unrestorable. Regular full backups provide recovery checkpoints.</li>
<li><strong>Restore time increases with chain length.</strong> Each incremental adds a prepare step. For very long chains, consider more frequent full backups.</li>
</ul>
<h2 id="try-it-out">Try It Out<a class="anchor-link" id="try-it-out"></a></h2>
<p>Incremental backups are available in Percona Operator for MySQL version 1.1.0 and later. If you&rsquo;re already running the operator, upgrade your CRDs and add a <code>type: incremental</code> schedule to your backup configuration.</p>
<p><!-- TODO --></p>
<ul>
<li><a href="">Operator documentation: Backups</a></li>
<li><a href="https://docs.percona.com/percona-xtrabackup/latest/create-incremental-backup.html" target="_blank" rel="noopener noreferrer">Percona XtraBackup: Incremental backups</a></li>
<li><a href="https://github.com/percona/percona-server-mysql-operator" target="_blank" rel="noopener noreferrer">GitHub: percona/percona-server-mysql-operator</a></li>
</ul>
<p>Have questions or feedback? Join the conversation on the <a href="https://forums.percona.com/" target="_blank" rel="noopener noreferrer">Percona Community Forum</a> or open an issue on GitHub. We&rsquo;d love to hear how incremental backups are working for your MySQL-on-Kubernetes deployments.</p>

<p>The post <a rel="nofollow" href="https://percona.community/blog/2026/04/17/incremental-backups-in-percona-kubernetes-operator-for-mysql/">Incremental backups in Percona Kubernetes Operator for MySQL</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>MariaDB’s Snapshot Isolation: A Fix That Breaks More Than It Fixes</title>
      <link>https://www.percona.com/blog/mariadbs-snapshot-isolation-a-fix-that-breaks-more-than-it-fixes/</link>
      <pubDate>Fri, 17 Apr 2026 07:58:28 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://www.percona.com/blog/">Blog - Percona</source>
      <description><![CDATA[<p>Jepsen’s analysis of MySQL 8.0.34 walked through a set of concurrency and isolation anomalies in InnoDB. MariaDB, which inherits the same codebase, took the report seriously and shipped a response: a new server variable called innodb_snapshot_isolation, turned on by default starting in 11.8. The announcement claims that with the flag enabled, Repeatable Read in MariaDB … Continued<br />
The post MariaDB’s Snapshot Isolation: A Fix That Breaks More Than It Fixes appeared first on Percona.</p>
<p>The post <a rel="nofollow" href="https://www.percona.com/blog/mariadbs-snapshot-isolation-a-fix-that-breaks-more-than-it-fixes/">MariaDB’s Snapshot Isolation: A Fix That Breaks More Than It Fixes</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p><a href="https://jepsen.io/analyses/mysql-8.0.34">Jepsen&rsquo;s analysis of MySQL 8.0.34</a> walked through a set of concurrency and isolation anomalies in InnoDB. MariaDB, which inherits the same codebase, took the report seriously and shipped a response: a new server variable called <code>innodb_snapshot_isolation</code>, turned on by default starting in 11.8. <a href="https://mariadb.com/resources/blog/isolation-level-violation-testing-and-debugging-in-mariadb/">The announcement</a> claims that with the flag enabled, Repeatable Read in MariaDB now satisfies snapshot isolation.</p>
<p>It&rsquo;s a good intention. The problem is what actually ships.</p>
<p>Two things fall apart once you start looking. First, the fix isn&rsquo;t complete &mdash; the anomalies Jepsen flagged can still be reproduced under concurrent load.</p>
<p>Second, it introduces incompatibilities with MySQL (in default enabled mode) &ndash; the moment the SNAPSHOT ISOLATION <em>does</em> fire as intended, it introduces <code>ERROR 1020: Record has changed since last read</code> into transactions that used to complete silently. That error now shows up in multiple applications, requiring to make changes either on code level or disabling <code>innodb_snapshot_isolation</code></p>
<h2>A quick refresher on what snapshot isolation promises<a class="anchor-link" id="a-quick-refresher-on-what-snapshot-isolation-promises"></a></h2>
<p>Snapshot isolation is supposed to let a transaction see a consistent view of the database taken at the moment it started.</p>
<p>Key behaviors of Snapshot Isolation:</p>
<ul>
<li>Consistency: A transaction sees data as it was at its start time, ignoring updates from concurrent transactions.</li>
<li>Non-Blocking Reads: Readers do not block writers, and writers do not block readers, reducing contention.</li>
<li>Conflict Detection: A transaction only commits if its updates do not conflict with concurrent updates made since the snapshot was taken.</li>
</ul>
<p>Two anomalies are specifically should not be present with Snapshot Isolation:</p>
<p><strong>Lost Update Anomaly:</strong>&nbsp;Two transactions read the same value, both modify it, and one overwrites the other. Two users increment a counter from 10. Both read 10, both write 11. The correct answer is 12.</p>
<p><strong>Non-Repeatable Read Anomaly:</strong>&nbsp;A transaction reads a row, someone else commits a change, and the first transaction reads the same row again and sees something different. Product price was $100, then it&rsquo;s $120 &mdash; all inside one transaction.</p>
<h2>What MySQL does today<a class="anchor-link" id="what-mysql-does-today"></a></h2>
<p>Plain Repeatable Read handles the simple case (two reads) fine:</p>
<table border="1">
<thead>
<tr>
<th>#</th>
<th>Session A</th>
<th>Session B</th>
<th>A sees</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td><code>SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; START TRANSACTION;</code></td>
<td></td>
<td></td>
</tr>
<tr>
<td>2</td>
<td><code>SELECT name FROM test_nrr WHERE id=0;</code></td>
<td></td>
<td><code>'Alice'</code></td>
</tr>
<tr>
<td>3</td>
<td></td>
<td><code>UPDATE test_nrr SET name='Bob' WHERE id=0;</code> <em>(autocommit)</em></td>
<td></td>
</tr>
<tr>
<td>4</td>
<td><code>SELECT name FROM test_nrr WHERE id=0;</code></td>
<td></td>
<td><code>'Alice'</code> &larr; <span style="color: #339966"><strong>RR holds</strong></span></td>
</tr>
<tr>
<td>5</td>
<td><code>COMMIT;</code></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<p>Add a write on Session A between the two reads, though, and RR does not hold (we get <strong>Non-Repeatable Read Anomaly</strong>):</p>
<table border="1">
<thead>
<tr>
<th>#</th>
<th>Session A</th>
<th>Session B</th>
<th>A sees</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td><code>SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; START TRANSACTION WITH CONSISTENT SNAPSHOT;</code></td>
<td></td>
<td></td>
</tr>
<tr>
<td>2</td>
<td><code>SELECT name FROM test_nrr WHERE id=0;</code></td>
<td></td>
<td><code>'Alice'</code></td>
</tr>
<tr>
<td>3</td>
<td></td>
<td><code>UPDATE test_nrr SET name='Bob' WHERE id=0;</code></td>
<td></td>
</tr>
<tr>
<td>4</td>
<td><code>UPDATE test_nrr SET gender=99 WHERE id=0;</code></td>
<td></td>
<td></td>
</tr>
<tr>
<td>5</td>
<td><code>SELECT name FROM test_nrr WHERE id=0;</code></td>
<td></td>
<td><code>'Bob'</code> &larr; <span style="color: #ff0000"><strong>Non-Repeatable Read</strong></span></td>
</tr>
</tbody>
</table>
<p>And here&rsquo;s<strong> Lost Update</strong> under plain Repeatable Read in MySQL:</p>
<table border="1">
<thead>
<tr>
<th>Time</th>
<th>Session A</th>
<th>Session B</th>
</tr>
</thead>
<tbody>
<tr>
<td>t1</td>
<td><code>BEGIN;</code></td>
<td></td>
</tr>
<tr>
<td>t2</td>
<td></td>
<td><code>BEGIN;</code></td>
</tr>
<tr>
<td>t3</td>
<td><code>SELECT counter FROM t WHERE id=1;</code> &rarr; 10</td>
<td></td>
</tr>
<tr>
<td>t4</td>
<td></td>
<td><code>SELECT counter FROM t WHERE id=1;</code> &rarr; 10</td>
</tr>
<tr>
<td>t5</td>
<td><code>UPDATE t SET counter=10+1 WHERE id=1; COMMIT;</code> <em>(counter = 11)</em></td>
<td></td>
</tr>
<tr>
<td>t6</td>
<td></td>
<td><code>UPDATE t SET counter=10+1 WHERE id=1; COMMIT;</code> <em>(still 11)</em></td>
</tr>
</tbody>
</table>
<p>Expected 12. Got 11. Session A&rsquo;s increment is gone.</p>
<p>For the full picture of what every isolation level actually guarantees across engines, Martin Kleppmann&rsquo;s Hermitage suite is the good reference: <a href="https://github.com/ept/hermitage/blob/master/mysql.md">github.com/ept/hermitage</a>.</p>
<h2>What MariaDB is supposed to do<a class="anchor-link" id="what-mariadb-is-supposed-to-do"></a></h2>
<p>With <code>innodb_snapshot_isolation=ON</code>, the <strong>Non-Repeatable Read </strong>scenario should stop at step 4 with:</p>
<table border="1">
<thead>
<tr>
<th>#</th>
<th>Session A</th>
<th>Session B</th>
<th>A sees</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td><code>SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; START TRANSACTION WITH CONSISTENT SNAPSHOT;</code></td>
<td></td>
<td></td>
</tr>
<tr>
<td>2</td>
<td><code>SELECT name FROM test_nrr WHERE id=0;</code></td>
<td></td>
<td><code>'Alice'</code></td>
</tr>
<tr>
<td>3</td>
<td></td>
<td><code>UPDATE test_nrr SET name='Bob' WHERE id=0;</code></td>
<td></td>
</tr>
<tr>
<td>4</td>
<td><code>UPDATE test_nrr SET gender=99 WHERE id=0;</code><br>
<strong><span style="color: #ff0000">ERROR 1020: Record has changed since last read in table &lsquo;test_nrr</span></strong>&lsquo;</td>
<td></td>
<td></td>
</tr>
<tr>
<td>5</td>
<td>TRANSACTION ROLLBACK</td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<p>And the <strong>Lost Update</strong> case should force whichever transaction tries to commit the stale write to roll back instead. That&rsquo;s the guarantee:</p>
<p>&nbsp;</p>
<table border="1">
<thead>
<tr>
<th>Time</th>
<th>Session A</th>
<th>Session B</th>
</tr>
</thead>
<tbody>
<tr>
<td>t1</td>
<td><code>BEGIN;</code></td>
<td></td>
</tr>
<tr>
<td>t2</td>
<td></td>
<td><code>BEGIN;</code></td>
</tr>
<tr>
<td>t3</td>
<td><code>SELECT counter FROM t WHERE id=1;</code> &rarr; 10</td>
<td></td>
</tr>
<tr>
<td>t4</td>
<td></td>
<td><code>SELECT counter FROM t WHERE id=1;</code> &rarr; 10</td>
</tr>
<tr>
<td>t5</td>
<td><code>UPDATE t SET counter=10+1 WHERE id=1; COMMIT;</code> <em>(counter = 11)</em></td>
<td></td>
</tr>
<tr>
<td>t6</td>
<td></td>
<td><code>UPDATE t SET counter=10+1 WHERE id=1; -&gt; <strong><span style="color: #ff0000">ERROR 1020: Record has changed since last read in table 'test_nrr</span></strong>'</code>
<p>TRANSACTION ROLLBACK</p></td>
</tr>
</tbody>
</table>
<p>That is in both cases MariaDB introduces</p>
<p><code>ERROR 1020: Record has changed since last read in table</code></p>
<h2>What actually happens<a class="anchor-link" id="what-actually-happens"></a></h2>
<p>Run it under concurrent load and both anomalies still turn up:</p>
<ul>
<li><strong>Lost Update:</strong> <a href="https://jira.mariadb.org/browse/MDEV-39263">MDEV-39263</a></li>
<li><strong>Non-Repeatable Read:</strong> <a href="https://jira.mariadb.org/browse/MDEV-39264">MDEV-39264</a></li>
</ul>
<p><code>ERROR 1020</code> fires most of the time, but&nbsp; not every time. A snapshot-isolation guarantee that only holds &ldquo;usually&rdquo; isn&rsquo;t a guarantee. The whole reason you pick an isolation level is for the bound it gives you.</p>
<h2>The another problem: compatibility<a class="anchor-link" id="the-another-problem-compatibility"></a></h2>
<p>Even when the error does fire when it should, MariaDB, by default, introduced a new failure mode into every client connected to the database. Almost nothing in the MySQL ecosystem catches <code>ERROR 1020</code> mid-transaction and retries. It sees an unexpected error, it bails.</p>
<p>Issues already filed against applications running on MariaDB 11.8:</p>
<ul>
<li>Laravel &mdash; <a href="https://github.com/laravel/framework/issues/56944">framework#56944</a></li>
<li>DOMjudge &mdash; <a href="https://github.com/DOMjudge/domjudge/issues/2848">domjudge#2848</a></li>
<li>Friendica &mdash; <a href="https://github.com/friendica/friendica/issues/15628">friendica#15628</a></li>
<li>webtrees &mdash; <a href="https://github.com/fisharebest/webtrees/issues/5177">webtrees#5177</a></li>
<li>PDO thread on <a href="https://stackoverflow.com/questions/79767034/mariadb-pdo-php-1020-error-record-has-changed-since-last-read-in-table">Stack Overflow</a></li>
</ul>
<p>These are apps that work on MySQL, work on earlier MariaDB, and now fail on 11.8. The clean workaround is turning the flag off &mdash; which defeats the point of shipping it on by default.</p>
<h2>Where that leaves us<a class="anchor-link" id="where-that-leaves-us"></a></h2>
<p>Jepsen pointed at real transactional anomalies and MariaDB tried to answer them.&nbsp; But a partial fix that silently breaks working applications isn&rsquo;t what &ldquo;drop-in MySQL replacement&rdquo; is supposed to mean. If the goal was to make migration easier, 11.8 went the other direction.</p>
<p>The post <a href="https://www.percona.com/blog/mariadbs-snapshot-isolation-a-fix-that-breaks-more-than-it-fixes/">MariaDB&rsquo;s Snapshot Isolation: A Fix That Breaks More Than It Fixes</a> appeared first on <a href="https://www.percona.com">Percona</a>.</p>

<p>The post <a rel="nofollow" href="https://www.percona.com/blog/mariadbs-snapshot-isolation-a-fix-that-breaks-more-than-it-fixes/">MariaDB’s Snapshot Isolation: A Fix That Breaks More Than It Fixes</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Where Do Users Get MariaDB Server From?</title>
      <link>https://mariadb.org/where-do-users-get-mariadb-server-from/</link>
      <pubDate>Fri, 17 Apr 2026 06:52:08 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.org/">MariaDB.org</source>
      <description><![CDATA[<p>We recently asked the community a simple but important question:<br />
What is the main source of the MariaDB Server you use?<br />
The answers provide a very interesting snapshot of how MariaDB is consumed in the real world today—and, perhaps more importantly, how different installation methods reflect different use cases and priorities. …<br />
Continue reading \"Where Do Users Get MariaDB Server From?\"<br />
The post Where Do Users Get MariaDB Server From? appeared first on MariaDB.org.</p>
<p>The post <a rel="nofollow" href="https://mariadb.org/where-do-users-get-mariadb-server-from/">Where Do Users Get MariaDB Server From?</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>We recently asked the community a simple but important question:</p>
<p><a href="https://mariadb.org/poll-mariadb-main-source/">What is the main source of the MariaDB Server you use?</a></p>
<p>The answers provide a very interesting snapshot of how MariaDB is consumed in the real world today&mdash;and, perhaps more importantly, how different installation methods reflect different use cases and priorities. &hellip; </p>
<p class="link-more"><a href="https://mariadb.org/where-do-users-get-mariadb-server-from/" class="more-link">Continue reading<span class="screen-reader-text"> &ldquo;Where Do Users Get MariaDB Server From?&rdquo;</span></a></p>
<p>The post <a rel="nofollow" href="https://mariadb.org/where-do-users-get-mariadb-server-from/">Where Do Users Get MariaDB Server From?</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>

<p>The post <a rel="nofollow" href="https://mariadb.org/where-do-users-get-mariadb-server-from/">Where Do Users Get MariaDB Server From?</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Why A Goat?</title>
      <link>https://www.percona.com/blog/why-a-goat/</link>
      <pubDate>Thu, 16 Apr 2026 13:10:53 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://goat.percona.com/blog/">Blog - Percona</source>
      <description><![CDATA[<p>New Brand. Same Independence. If you read today’s announcement, you know Percona has a lot to say about what’s broken in modern data infrastructure. Lock-in dressed up as openness. Costs that climb while control shrinks. Vendors who made “managed” mean giving up visibility instead of gaining it. When we decided to stop being quiet about … Continued<br />
The post Why A Goat? appeared first on Percona.</p>
<p>The post <a rel="nofollow" href="https://www.percona.com/blog/why-a-goat/">Why A Goat?</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<h2><span style="font-weight: 400">New Brand. Same Independence.<br>
</span><a class="anchor-link" id="new-brand-same-independence"></a></h2>
<p><span style="font-weight: 400">If you read today&rsquo;s announcement, you know Percona has a lot to say about what&rsquo;s broken in modern data infrastructure. Lock-in dressed up as openness. Costs that climb while control shrinks. Vendors who made &ldquo;managed&rdquo; mean giving up visibility instead of gaining it.</span></p>
<p><span style="font-weight: 400">When we decided to stop being quiet about all of it, to build an identity that actually reflected what Percona believes and what Percona does, we had a choice to make. Every brand needs a symbol.&nbsp;</span></p>
<h2><span style="font-weight: 400">We picked a goat.</span><a class="anchor-link" id="we-picked-a-goat"></a></h2>
<p><span style="font-weight: 400">Not a lion. Not an eagle. Not something abstract that a committee agreed was inoffensive. A goat. And if that surprises you, you probably haven&rsquo;t spent much time thinking about goats.</span></p>
<h2><span style="font-weight: 400">Why a Goat?</span><a class="anchor-link" id="why-a-goat"></a></h2>
<p><span style="font-weight: 400">Most tech company mascots are chosen to project power or aspiration. They roar or soar or look good on a t-shirt at a conference. That&rsquo;s fine if your brand is built on image.</span></p>
<h2><span style="font-weight: 400">Ours isn&rsquo;t.</span><a class="anchor-link" id="ours-isnt"></a></h2>
<p><span style="font-weight: 400">Percona has spent 20 years doing the unglamorous, load-bearing work of keeping databases running, patching at 3:00 a.m., telling customers the honest answer when it wasn&rsquo;t the comfortable one, building freely available open source software because we believed the industry deserved better than what vendors were offering. None of that is lion territory. It&rsquo;s goat territory.</span></p>
<p><span style="font-weight: 400">Goats don&rsquo;t perform. They just get the job done, wherever you put them. That&rsquo;s Percona.</span></p>
<p>&nbsp;</p>
<h2><span style="font-weight: 400">Six Things the Goat Gets Right</span><a class="anchor-link" id="six-things-the-goat-gets-right"></a></h2>
<p><span style="font-weight: 400">&nbsp;</span></p>
<h3>Resilient by nature.<a class="anchor-link" id="resilient-by-nature"></a></h3>
<p><span style="font-weight: 400">Goats survive where other animals don&rsquo;t bother trying. Percona builds for always-on, mission-critical workloads, the ones where downtime isn&rsquo;t an inconvenience, it&rsquo;s a crisis. Your database goes down at 2:00 a.m. on a holiday weekend? We&rsquo;re already on it. That&rsquo;s not a marketing line. That&rsquo;s the job.</span></p>
<h3>Open and independent.<a class="anchor-link" id="open-and-independent"></a></h3>
<p><span style="font-weight: 400">Goats don&rsquo;t belong to anyone. Neither does open source, when it&rsquo;s done right. Percona has spent its entire existence making sure organizations can run technologies like MySQL, PostgreSQL, MongoDB, Redis and Valkey without a single vendor holding the keys. The goat is a symbol of that freedom. The brand is the declaration of it.</span></p>
<h3>Naturally adaptable.<a class="anchor-link" id="naturally-adaptable"></a></h3>
<p><span style="font-weight: 400">Mountain goats thrive on cliff faces, in forests, on open plains. Percona software runs on-premises, in the cloud, and across hybrid environments with the same reliability. Your infrastructure changes. Your database platform shouldn&rsquo;t have to.</span></p>
<h3>Sure-footed in complexity.<a class="anchor-link" id="sure-footed-in-complexity"></a></h3>
<p><span style="font-weight: 400">Goats navigate terrain that would stop most animals cold. Percona engineers work in the same kind of environments: sprawling multi-database estates, legacy migrations, compliance frameworks that make your head spin. We don&rsquo;t freeze up when the terrain gets steep. That&rsquo;s what 20 years of experience looks like.</span></p>
<h3>Trusted guide.<a class="anchor-link" id="trusted-guide"></a></h3>
<p><span style="font-weight: 400">In mountainous regions, goats have led other animals along safe paths for centuries. Percona does the same for database teams navigating scale, modernization, and architectural change. We&rsquo;ve walked the path before. We know where the drop-offs are.</span></p>
<h3>Community driven.<a class="anchor-link" id="community-driven"></a></h3>
<p><span style="font-weight: 400">Mountain goats aren&rsquo;t herd animals. They don&rsquo;t move in packs or wait for the group to decide. They operate independently, come together when it matters, and the strongest ones lead. Percona&rsquo;s community works the same way, contributors, forum regulars, Percona Live speakers, the engineer who filed that bug report at midnight, each of them doing the work on their own terms, sharing knowledge freely when it counts. No paywalls. No gatekeeping. Just people who know their terrain and aren&rsquo;t shy about it.</span></p>
<p>&nbsp;</p>
<h2><span style="font-weight: 400">Same Percona. Only Louder.</span><a class="anchor-link" id="same-percona-only-louder"></a></h2>
<p><span style="font-weight: 400">Here&rsquo;s what the new brand isn&rsquo;t: a reinvention. Percona hasn&rsquo;t changed what it believes or what it does. What&rsquo;s changed is that we have 20 years of credibility behind us, a clearer picture of what&rsquo;s broken in the industry, and no remaining appetite for being polite about it.</span></p>
<p><span style="font-weight: 400">The goat isn&rsquo;t a departure from who Percona has always been. It&rsquo;s the most honest representation of it we&rsquo;ve ever put on paper.</span></p>
<p><span style="font-weight: 400">The Way Is Open. It always was. We&rsquo;re just saying it louder now.</span></p>
<p><span style="font-weight: 400">*Want to know more about what&rsquo;s driving the rebrand? <a href="https://www.globenewswire.com/news-release/2026/04/16/3275419/0/en/Percona-Declares-The-Way-is-Open-in-Bold-Rebrand-as-the-Industry-s-Loudest-Challenger.html" target="_blank" rel="noopener">Read the full announcement here</a></span></p>
<p>The post <a href="https://www.percona.com/blog/why-a-goat/">Why A Goat?</a> appeared first on <a href="https://www.percona.com">Percona</a>.</p>

<p>The post <a rel="nofollow" href="https://www.percona.com/blog/why-a-goat/">Why A Goat?</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>MongoDB Query Plan Cache Explained: Performance, Pitfalls, and Re-Planning</title>
      <link>https://www.percona.com/blog/mongodb-query-plan-cache-explained-performance-pitfalls-and-re-planning/</link>
      <pubDate>Mon, 13 Apr 2026 21:11:36 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://goat.percona.com/blog/">Blog - Percona</source>
      <description><![CDATA[<p>When MongoDB receives a query, it performs the following steps: Evaluate the available indexes that could be used. Generate and test multiple execution plans using candidate indexes. Measure their performance during a trial phase. Select the fastest plan (the winning plan) and execute the query. These steps are known as query planning, and they are … Continued<br />
The post MongoDB Query Plan Cache Explained: Performance, Pitfalls, and Re-Planning appeared first on Percona.</p>
<p>The post <a rel="nofollow" href="https://www.percona.com/blog/mongodb-query-plan-cache-explained-performance-pitfalls-and-re-planning/">MongoDB Query Plan Cache Explained: Performance, Pitfalls, and Re-Planning</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>When MongoDB receives a query, it performs the following steps:</p>
<ul>
<li>Evaluate the available indexes that could be used.</li>
<li>Generate and test multiple execution plans using candidate indexes.</li>
<li>Measure their performance during a trial phase.</li>
<li>Select the fastest plan (the winning plan) and execute the query.</li>
</ul>
<p>These steps are known as <strong>query planning</strong>, and they are expensive in terms of CPU, memory, and potentially disk utilization. Calculating a query plan for every single query would significantly impact database performance.</p>
<p>Fortunately, MongoDB does not repeat this process for every query.</p>
<p>Once a query plan has been generated, it is stored in an in-memory cache associated with the collection: the Query Plan Cache. Each collection has its own independent cache.</p>
<p>The Query Plan Cache stores:</p>
<ul>
<li>The <strong>query shape</strong> (filter conditions, projection, sort, etc.)</li>
<li>The <strong>winning plan</strong> (indexes and access methods)</li>
<li>Additional metadata, such as the expected performance of the plan (measured in <strong>works</strong>, an abstract unit of measurement that MongoDB uses internally to quantify the resource consumption of a query execution plan)</li>
</ul>
<p>Every subsequent query with the same shape retrieves the winning plan directly from the cache instead of triggering query planning again.</p>
<ul>
<li>Benefits are:</li>
<li>Less CPU utilization</li>
<li>Reduced latencyFaster recurring queries</li>
<li>Better overall scalability</li>
</ul>
<p>&nbsp;</p>
<h1>Let&rsquo;s test it<a class="anchor-link" id="lets-test-it"></a></h1>
<p>Let&rsquo;s explore the Query Plan Cache and see how to inspect and manage it.</p>
<h2>Create a Test Collection<a class="anchor-link" id="create-a-test-collection"></a></h2>
<p>Create an <i>orders</i> collection with 1 million documents using the following script in the shell:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">use queryCacheLab
db.orders.drop()

const statuses = ["NEW", "PAID", "SHIPPED", "CANCELLED"]

const TOTAL_DOCS = 1000000
const BATCH_SIZE = 10000

let bulk = []
let batchNumber = 0
let insertedDocs = 0

const startTime = new Date()

for (let i = 0; i &amp;lt; TOTAL_DOCS; i++) {
 &nbsp;bulk.push({
&nbsp;&nbsp;&nbsp;&nbsp;orderId: i,
&nbsp;&nbsp;&nbsp;&nbsp;customerId: Math.floor(Math.random() * 50000),
&nbsp;&nbsp;&nbsp;&nbsp;status: statuses[Math.floor(Math.random() * 4)],
&nbsp;&nbsp;&nbsp;&nbsp;total: Math.floor(Math.random() * 1000),
&nbsp;&nbsp;&nbsp;&nbsp;createdAt: new Date(2024, 0, 1 + Math.floor(Math.random() * 365))
&nbsp;&nbsp;})

&nbsp;&nbsp;if (bulk.length === BATCH_SIZE) {
&nbsp;&nbsp;&nbsp;&nbsp;db.orders.insertMany(bulk, { ordered: false })
&nbsp;&nbsp;&nbsp;&nbsp;batchNumber++
&nbsp;&nbsp;&nbsp;&nbsp;insertedDocs += bulk.length
&nbsp;&nbsp;&nbsp;&nbsp;bulk = []
&nbsp;&nbsp;&nbsp;&nbsp;const elapsed = (new Date() - startTime) / 1000
&nbsp;&nbsp;&nbsp;&nbsp;const percent = ((insertedDocs / TOTAL_DOCS) * 100).toFixed(2)
&nbsp;&nbsp;&nbsp;&nbsp;print(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`Batch ${batchNumber} completato | ` +
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`Inserted documents: ${insertedDocs}/${TOTAL_DOCS} (${percent}%) | ` +
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`Time elapsed: ${elapsed.toFixed(2)} sec`
&nbsp;&nbsp;&nbsp;&nbsp;)
&nbsp;&nbsp;}
}
// Insert eventual remaining documents
if (bulk.length &amp;gt; 0) {
&nbsp;&nbsp;db.orders.insertMany(bulk, { ordered: false })
&nbsp;&nbsp;insertedDocs += bulk.length
&nbsp;&nbsp;batchNumber++
}
const totalTime = (new Date() - startTime) / 1000
print("====================================")
print(`Inserts completed`)
print(`Total batches: ${btchNumber}`)
print(`Total documents: ${insertedDos}`)
print(`Time: ${totalTime.toFixed(2)} ses`)
print("====================================")</pre>
<p>&nbsp;</p>
<h2>Create Indexes<a class="anchor-link" id="create-indexes"></a></h2>
<p>Create secondary indexes, so MongoDB can evaluate multiple execution plans:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">db.orders.createIndex({ status: 1 })
db.orders.createIndex({ customerId: 1 })
db.orders.createIndex({ status: 1, customerId: 1 })</pre>
<p>&nbsp;</p>
<h2>Generate and Inspect a Cache Plan<a class="anchor-link" id="generate-and-inspect-a-cache-plan"></a></h2>
<p>Run the query a few times to ensure the plan is cached:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">db.orders.find({
&nbsp;&nbsp;status: "PAID",
&nbsp;&nbsp;customerId: 1234
})</pre>
<p>Inspect the execution plan:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">db.orders.find({
&nbsp;&nbsp;status: "PAID",
&nbsp;&nbsp;customerId: 1234
}).explain("executionStats")</pre>
<p>Relevant details:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">&hellip;
&nbsp;&nbsp;&nbsp;&nbsp;winningPlan: {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;isCached: true,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;stage: 'FETCH',
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inputStage: {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;stage: 'IXSCAN',
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;keyPattern: { status: 1, customerId: 1 },
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;indexName: 'status_1_customerId_1',
&hellip;
&nbsp;&nbsp;executionStats: {
&nbsp;&nbsp;&nbsp;&nbsp;executionSuccess: true,
&nbsp;&nbsp;&nbsp;&nbsp;nReturned: 6,
&nbsp;&nbsp;&nbsp;&nbsp;executionTimeMillis: 2,
&nbsp;&nbsp;&nbsp;&nbsp;totalKeysExamined: 6,
&nbsp;&nbsp;&nbsp;&nbsp;totalDocsExamined: 6,
&hellip;</pre>
<p>The winning plan:</p>
<ul>
<li>is cached</li>
<li>uses the compound index</li>
<li>shows good execution metrics</li>
</ul>
<p>The Query Plan Cache is now populated with this optimal plan.</p>
<h2>Inspecting the Query Plan Cache<a class="anchor-link" id="inspecting-the-query-plan-cache"></a></h2>
<p>You can inspect the cache using :</p>
<pre class="urvanov-syntax-highlighter-plain-tag">db.orders.getPlanCache().list()
[
&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;version: '1',
&nbsp;&nbsp;&nbsp;&nbsp;queryHash: '706C5F81',
&nbsp;&nbsp;&nbsp;&nbsp;planCacheShapeHash: '706C5F81',
&nbsp;&nbsp;&nbsp;&nbsp;planCacheKey: '2189DB6F',
&nbsp;&nbsp;&nbsp;&nbsp;isActive: true,
&nbsp;&nbsp;&nbsp;&nbsp;works: Long('7'),
&nbsp;&nbsp;&nbsp;&nbsp;worksType: 'works',
&nbsp;&nbsp;&nbsp;&nbsp;timeOfCreation: ISODate('2026-02-12T13:53:05.349Z'),
&nbsp;&nbsp;&nbsp;&nbsp;createdFromQuery: {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;query: { status: 'PAID', customerId: 1234 },
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sort: {},
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;projection: {}
&nbsp;&nbsp;&nbsp;&nbsp;},
&nbsp;&nbsp;&nbsp;&nbsp;cachedPlan: {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;stage: 'FETCH',
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inputStage: {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;stage: 'IXSCAN',
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;keyPattern: { status: 1, customerId: 1 },
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;indexName: 'status_1_customerId_1',
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;isMultiKey: false,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;multiKeyPaths: { status: [], customerId: [] },
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;isUnique: false,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;isSparse: false,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;isPartial: false,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;indexVersion: 2,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;direction: 'forward',
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;indexBounds: {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;status: [ '["PAID", "PAID"]' ],
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;customerId: [ '[1234, 1234]' ]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;},
&hellip;
&hellip;</pre>
<p>Alternatively, via aggregation:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">db.orders.aggregate( [
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ $planCacheStats: { } }
] )</pre>
<p>From the cache, you can see:</p>
<ul>
<li>Unique identifiers for the query shape (<strong>queryHash</strong>, <strong>planCacheKey</strong>)</li>
<li>The cached execution plan (<strong>cachedPlan</strong>)</li>
<li>The expected cost (<strong>works</strong>)</li>
</ul>
<h2>Reusing the Cached Plan<a class="anchor-link" id="reusing-the-cached-plan"></a></h2>
<p>Now run the same query shape with different values:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">db.orders.find({
&nbsp;&nbsp;status: "PAID",
&nbsp;&nbsp;customerId: 4000
}).explain("executionStats")</pre>
<p>From <strong>explain()</strong>, you will see:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">winningPlan: {
&nbsp;&nbsp;isCached: true,
&nbsp;&nbsp;...
}
executionStages: {
&nbsp;&nbsp;isCached: true,
&nbsp;&nbsp;...
}
queryHash: '4C4D18FFE78D0BC85621B75A7F1C338AEB0F0A2D5E438A5A6DF815198F64283D'
planCacheKey: '2189DB6F'</pre>
<p>This confirms the plan was reused from the cache (<strong>isCached: true</strong> and look at the referenced <strong>planCacheKey</strong>).</p>
<h2>Verifying Cache Usage with the Profiler<a class="anchor-link" id="verifying-cache-usage-with-the-profiler"></a></h2>
<p>If the profiler is enabled, you can check into the system.profile collection of your database:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">db.system.profile.find({}).sort({ts: -1}).limit(1)
[
&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;op: 'query',
&nbsp;&nbsp;&nbsp;&nbsp;ns: 'queryCacheLab.orders',
&nbsp;&nbsp;&nbsp;&nbsp;command: {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;find: 'orders',
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;filter: { status: 'PAID', customerId: 1234 },
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lsid: { id: UUID('3a1f019f-1836-4c76-96c8-3ae596d01108') },
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'$clusterTime': {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;clusterTime: Timestamp({ t: 1770912932, i: 1 }),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;signature: {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hash: Binary.createFromBase64('QOFvrL9a4DjdLUE0PEzVLvxHukI=', 0),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;keyId: Long('7605947023161819142')
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'$db': 'queryCacheLab'
&nbsp;&nbsp;&nbsp;&nbsp;},
&nbsp;&nbsp;&nbsp;&nbsp;keysExamined: 13,
&nbsp;&nbsp;&nbsp;&nbsp;docsExamined: 13,
&nbsp;&nbsp;&nbsp;&nbsp;fromPlanCache: true,
&nbsp;&nbsp;&nbsp;&nbsp;nBatches: 1,
&nbsp;&nbsp;&nbsp;&nbsp;cursorExhausted: true,
&nbsp;&nbsp;&nbsp;&nbsp;numYield: 0,
&nbsp;&nbsp;&nbsp;&nbsp;nreturned: 13,
&nbsp;&nbsp;&nbsp;&nbsp;planCacheShapeHash: '706C5F81',
 &nbsp;&nbsp;&nbsp;queryHash: '706C5F81',
&nbsp;&nbsp;&nbsp;&nbsp;planCacheKey: '2189DB6F',
&nbsp;&nbsp;&nbsp;&nbsp;queryShapeHash: '4C4D18FFE78D0BC85621B75A7F1C338AEB0F0A2D5E438A5A6DF815198F64283D',
&nbsp;&nbsp;&nbsp;&nbsp;queryFramework: 'classic',
&hellip;
&hellip;</pre>
<p>This also confirms that the cached plan was used (<strong>fromPlanCache: true</strong> and look at the referenced <strong>planCacheKey</strong>).</p>
<h1>When the Cached Plan becomes Suboptimal<a class="anchor-link" id="when-the-cached-plan-becomes-suboptimal"></a></h1>
<p>Let&rsquo;s degrade the selectivity by setting all orders to <b>status=&rsquo;PAID&rsquo;</b>.</p>
<pre class="urvanov-syntax-highlighter-plain-tag">db.orders.updateMany(
&nbsp;&nbsp;{},
&nbsp;&nbsp;{ $set: { status: "PAID" } }
)</pre>
<p>Now <em>status</em> is no longer selective.</p>
<p>Running the original query again:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">db.orders.find({
&nbsp;&nbsp;status: "PAID",
&nbsp;&nbsp;customerId: 1234
}).explain("executionStats")</pre>
<p>You may notice:</p>
<ul>
<li>Higher <strong>keysExamined</strong></li>
<li>Increased <strong>executionTimeMillis</strong></li>
</ul>
<p>MongoDB is still using the cached plan, even though data distribution has changed.</p>
<p>This could be the main concern about the cached query plans. If the data distribution changes without being so bad, MongoDB continues to use that plan. This way it could happen that the cached plan is no longer the best one.</p>
<h1>Manually clearing the cache<a class="anchor-link" id="manually-clearing-the-cache"></a></h1>
<p>Clear all cached plans and check it is really empty:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">db.orders.getPlanCache().clear()
db.orders.getPlanCache().list()</pre>
<p>Or remove a specific plan by providing the query shape:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">db.orders.getPlanCache().clearPlansByQuery({&nbsp;
&nbsp;&nbsp;status: 'PAID',&nbsp;
&nbsp;&nbsp;customerId: 1234&nbsp;
})</pre>
<p>&nbsp;</p>
<h1>Query Plan Cache invalidation<a class="anchor-link" id="query-plan-cache-invalidation"></a></h1>
<p>Since the data changes over the time, the query plan for a specific query can change as well. The winning plan depends on:</p>
<ul>
<li>Available indexes</li>
<li>Data distribution.</li>
</ul>
<p>&nbsp;</p>
<p>Doing massive inserts, updates or deletions can alter the distribution of the data and a plan that was optimal yesterday, cannot be optimal today. This means the query plan needs to be recalculated from time to time to make sure MongoDB can rely on the most up-to-date and optimized one.</p>
<p>Plans are recalculated <b>only when invalidated</b>, not on a schedule.</p>
<p>Invalidation happens when:</p>
<ul>
<li>An index is created</li>
<li>An index is dropped</li>
<li><strong>mongod</strong> restarts</li>
<li>The cached plan becomes inefficient. MongoDB compares actual performance with expected performance (<strong>works</strong>). If the deviation is large (different order of magnitude), the plan is invalidated and replanned</li>
</ul>
<h1>The Re-Planning issue<a class="anchor-link" id="the-re-planning-issue"></a></h1>
<p>Everything works well until you face the re-planning issue.</p>
<p>It could happen that every query triggers the invalidation of the cached plan, and so a re-planning is needed continuously. You can easily identify when this happens because usually you can notice a significant CPU utilization increase.</p>
<p>You can also verify in the mongod log what is happening:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">{"t":{"$date":"2025-12-29T18:50:17.970+00:00"},"s":"I",&nbsp; "c":"COMMAND",&nbsp; "id":51803, &nbsp; 
"ctx":"conn4577913","msg":"Slow query","attr":{"type":"command",......
"planningTimeMicros":215107053,"keysExamined":46283,"docsExamined":46283,
"hasSortStage":true,"fromMultiPlanner":true,
"replanned":true,
"replanReason":"cached plan was less efficient than expected: expected trial execution 
to take 2 works but it took at least 20 works",
"nBatches":1,"cursorExhausted":true,"numYields":15603,"nreturned":0,
"queryHash":"6950AFA3","planCacheKey":"F8B9BF2F",
"queryFramework":"classic",......."durationMillis":215107}}</pre>
<p>If you see fields like <b>&ldquo;replanned&rdquo;:true</b>, and <b>&ldquo;replanReason&rdquo;:&rdquo;cached plan was less efficient than expected: expected trial execution to take 2 works but it took at least 20 works&rdquo;</b>, it means the query required re-planning.</p>
<p>Look at the <b>&ldquo;planningTimeMicros&rdquo;:215107053</b> and compare it with <b>&ldquo;durationMillis&rdquo;:215107; </b>almost the entire time was spent in the query planning.</p>
<p>Usually, a query replanned is also a slow query. Then the occurrences are easy to identify by filtering the log with <b>&ldquo;id&rdquo;:51803. </b>This is the unique identifier for all slow query entries in the log.</p>
<p>Common causes of continuous re-planning:</p>
<ul>
<li>Having unstable queries that are data-dependent
<ul>
<li>Indexed values are not evenly distributed: a plan is good for specific values of the filter conditions and not for others</li>
</ul>
</li>
<li>Having right indexes but not selective enough</li>
<li>There are 2 or more plans providing the same performance. Little variations in the data can change the real performance of the queries</li>
<li>The cardinality of indexed fields changes rapidly. This could happen when:
<ul>
<li>Doing massive inserts</li>
<li>Doing massive deletes</li>
<li>Having TTL indexes that delete lots of documents</li>
<li>Using capped collection that overwrites lots of documents</li>
</ul>
</li>
<li>Using <strong>$or</strong>, <strong>$in</strong> or <strong>$regex</strong> operators can lead to completely different results depending on the number of items you specify in the query</li>
</ul>
<p>Write-intensive workloads are generally more sensitive than read-intensive ones.</p>
<p>In short: <b>the re-planning loop occurs when data changes faster than the planner can adapt.</b></p>
<h1>Mitigating Re-Planning<a class="anchor-link" id="mitigating-re-planning"></a></h1>
<p>There is no universal fix, but you can</p>
<ul>
<li>Analyze the affected query and create more specific and selective indexes</li>
<li>Avoid overly generic queries that can be affected by the uneven data distribution</li>
<li>Reduce the number of items when using <b>$or</b> or <b>$in</b> operators. Eventually split the query in multiple smaller queries</li>
<li>Regularly analyze <b>explain(&ldquo;executionStats&rdquo;)</b> for monitoring the execution plan</li>
<li>Use <b>hint()</b> to force the utilization of a specific index in extreme cases.
<ul>
<li>Using <em>hint()</em> in production is not ideal, but in pathological situations it can immediately stabilize performance while you investigate properly.</li>
</ul>
</li>
</ul>
<p>About hint(), there is a new feature available in MongoDB 8.0 that provides a way to hint a specific index for any query shape for the entire cluster. More details on this <a href="https://www.google.com/url?q=https://www.mongodb.com/docs/manual/reference/command/setQuerySettings" rel="nofollow">page.</a></p>
<h1>Query Plan Cache is Local<a class="anchor-link" id="query-plan-cache-is-local"></a></h1>
<p>Important to remember is that the Query Plan Cache is:</p>
<ul>
<li>Per collection</li>
<li>Local to each mongod instance</li>
</ul>
<p>There is no cluster-wide global cache.</p>
<p>In a sharded cluster:</p>
<ul>
<li>Each shard may have a different plan for every query</li>
<li>PRIMARY and SECONDARY nodes may differ as well if you created different indexes</li>
<li>Chunk migrations can influence the plan selection</li>
</ul>
<p>Starting from version 6.3 it is possible configuring the size of the Query Plan Cache using the parameter <b>planCacheSize</b>. It can be set to a percentage of available memory like for example &ldquo;8.5%&rdquo; or to a fixed size in MB or GB, like for example&nbsp; &ldquo;100MB&rdquo; or &ldquo;1GB&rdquo;. It defaults to 5%.</p>
<p>For more details look at this <a href="https://www.mongodb.com/docs/manual/reference/parameters/#mongodb-parameter-param.planCacheSize" rel="nofollow">page</a>.</p>
<h1>Conclusion<a class="anchor-link" id="conclusion"></a></h1>
<p>The Query Plan Cache is a powerful MongoDB feature that stabilizes and improves query performance by avoiding repeated planning. This also helps to increase scalability.</p>
<p>However, in specific scenarios&mdash;especially with unstable data distribution or low-selectivity indexes&mdash;the re-planning loop can cause high CPU usage and degraded performance.</p>
<p>Understanding how the cache works, how invalidation happens, and how to detect re-planning issues is essential to maintaining predictable and efficient query performance.</p>
<p>&nbsp;</p>
<p>The post <a href="https://www.percona.com/blog/mongodb-query-plan-cache-explained-performance-pitfalls-and-re-planning/">MongoDB Query Plan Cache Explained: Performance, Pitfalls, and Re-Planning</a> appeared first on <a href="https://www.percona.com">Percona</a>.</p>

<p>The post <a rel="nofollow" href="https://www.percona.com/blog/mongodb-query-plan-cache-explained-performance-pitfalls-and-re-planning/">MongoDB Query Plan Cache Explained: Performance, Pitfalls, and Re-Planning</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Auditing Login Attempts in MySQL and MariaDB</title>
      <link>https://www.percona.com/blog/auditing-login-attempts-in-mysql-and-mariadb/</link>
      <pubDate>Mon, 13 Apr 2026 21:08:26 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://www.percona.com/blog/">Blog - Percona</source>
      <description><![CDATA[<p>My colleague Miguel wrote about ways to audit login attempts in MySQL over 13 years ago, and this is still a relevant subject. I decided to refresh this topic to include some important changes since then. Very often, it is important to track login attempts to our databases due to security reasons as well as … Continued<br />
The post Auditing Login Attempts in MySQL and MariaDB appeared first on Percona.</p>
<p>The post <a rel="nofollow" href="https://www.percona.com/blog/auditing-login-attempts-in-mysql-and-mariadb/">Auditing Login Attempts in MySQL and MariaDB</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p><img decoding="async" loading="lazy" class="alignright wp-image-105058 size-medium" src="https://www.percona.com/wp-content/uploads/2026/04/ACL.png" alt="" width="194" height="300">My colleague Miguel wrote about ways to audit login attempts in MySQL over <a href="https://www.percona.com/blog/auditing-login-attempts-in-mysql/">13 years ago</a>, and this is still a relevant subject. I decided to refresh this topic to include some important changes since then.</p>
<p>Very often, it is important to track login attempts to our databases due to security reasons as well as to catch application misconfigurations. I&rsquo;ll focus here on the most convenient ways to log authentication attempts. While auditing all client connections is usually pointless on busy production systems, when even thousands of new client sessions may be authenticating per second, let&rsquo;s concentrate especially on the failed ones.</p>
<h3>The Error Log<a class="anchor-link" id="the-error-log"></a></h3>
<p>All MySQL and MariaDB variants have an easy way of logging failed authentication attempts in the standard error log via elevated log verbosity. To enable it, in older MySQL versions up to 5.7, as well as in all MariaDB versions, set <code><a href="https://mariadb.com/docs/server/server-management/server-monitoring-logs/error-log#configuring-the-error-log-verbosity" rel="nofollow">log_warnings</a></code><code> = 2 (or higher)</code>.</p>
<p>In MySQL 5.7+, the role of setting the error log talkativeness was moved to the new variable: <code><a href="https://dev.mysql.com/doc/refman/8.4/en/server-system-variables.html#sysvar_log_error_verbosity" rel="nofollow">log_error_verbosity</a></code>. MySQL 8.0+ no longer recognizes <code>log_warnings</code>. To log failed logins, set <code>log_error_verbosity = 3 </code>instead.</p>
<p>An example log entry when login credentials were incorrect may look like this:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">2026-02-24T20:36:09.186218Z 22 [Note] [MY-010926] [Server] Access denied for user 'myuser2'@'192.168.121.12' (using password: YES)</pre>
<p>Another error occurs when user credentials are fine, but the user does not have privileges to access a given database:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">2026-02-24T23:12:19.600451Z 35 [Note] [MY-010914] [Server] Access denied for user 'myuser'@'192.168.46.%' to database 'test1'</pre>
<p>Now, the problem with this is that the above note will only be printed when there is a system user allowing the source hostname, IP address, or subnet, and the actual username authentication phase is engaged. <strong>When the host is rejected early, we will not find anything in the error log!</strong> Only the client side will receive a rejection message, like this one:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">$ mysql -h192.168.46.20 -uuser
ERROR 1130 (HY000): Host '192.168.46.13' is not allowed to connect to this MySQL server</pre>
<p>Therefore, the error log cannot provide the complete information about failed login attempts if some are incoming from undefined hosts. Btw, the general log does not log these either.</p>
<h3>The Audit Log (old type)<a class="anchor-link" id="the-audit-log-old-type"></a></h3>
<p>The traditional Audit Log Plugin feature, available in all recent MySQL variants, allows us to limit logging for connection activities, while we can ignore other queries. Unfortunately, <strong>we cannot log only failed logins</strong>, so the log may grow very fast when applications actively open new connections, and further filtering for failed attempts has to be done externally.</p>
<p>In <a href="https://docs.percona.com/percona-server/8.0/audit-log-plugin.html">Percona Audit Log Plugin</a>, it can be done via the policy setting: <code>audit_log_policy = LOGINS</code>.</p>
<p>An example of a netcat <strong>TCP probe</strong> will result in the following audit log entry:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">tail -1 /var/lib/mysql/audit.log |jq
{
  "audit_record": {
    "name": "Connect",
    "record": "2138_2026-02-26T09:32:27",
    "timestamp": "2026-02-26T09:33:54Z",
    "connection_id": "13",
    "status": 1158,
    "user": "",
    "priv_user": "",
    "os_login": "",
    "proxy_user": "",
    "host": "test-host1",
    "ip": "192.168.46.12",
    "db": ""
  }
}</pre>
<p>The entry provides a status error code:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">$ perror 1158
MySQL error code MY-001158 (ER_NET_READ_ERROR): Got an error reading communication packets</pre>
<p>Interestingly, the corresponding error log entry has the same message with a different code:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">2026-02-26T09:33:54.917323Z 13 [Note] [MY-010914] [Server] Got an error reading communication packets</pre>
<p>Another example of an unknown user login attempt:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">{
  "audit_record": {
    "name": "Connect",
    "record": "2142_2026-02-26T09:32:27",
    "timestamp": "2026-02-26T09:39:45Z",
    "connection_id": "17",
    "status": 1045,
    "user": "wronguser",
    "priv_user": "",
    "os_login": "",
    "proxy_user": "",
    "host": "test-host1",
    "ip": "192.168.46.12",
    "db": ""
  }
}</pre>
<p>Here, we can determine that the user part is wrong, as the <code>priv_user</code> field is empty.</p>
<p>A typical legit client session will have two entries, with status &ldquo;0&rdquo;, i.e:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">{"audit_record":{"name":"Connect","record":"2145_2026-02-26T09:32:27","timestamp":"2026-02-26T09:42:27Z","connection_id":"19","status":0,"user":"myuser","priv_user":"myuser","os_login":"","proxy_user":"","host":"test-host1","ip":"192.168.46.13","db":""}}
{"audit_record":{"name":"Quit","record":"2146_2026-02-26T09:32:27","timestamp":"2026-02-26T09:42:27Z","connection_id":"19","status":0,"user":"myuser","priv_user":"myuser","os_login":"","proxy_user":"","host":"test-host1","ip":"192.168.46.13","db":""}}</pre>
<p>In the <a href="https://mariadb.com/docs/server/reference/plugins/mariadb-audit-plugin/mariadb-audit-plugin-options-and-system-variables#server_audit_events" rel="nofollow">MariaDB Audit Plugin</a>, connection events can be logged via the <code>server_audit_events = CONNECT</code> setting. An example logging attempt with the wrong password would be seen as:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">20260226 10:52:48,test-host1,root,localhost,8,0,FAILED_CONNECT,,,1045
20260226 10:52:48,test-host1,root,localhost,8,0,DISCONNECT,,,0</pre>

<h2>The Audit Log Filter (new type)<a class="anchor-link" id="the-audit-log-filter-new-type"></a></h2>
<p>The new audit log functionality comes as a <a href="https://docs.percona.com/percona-server/8.0/install-audit-log-filter.html">plugin</a> in versions 8.0.x or a <a href="https://docs.percona.com/percona-server/8.4/install-audit-log-filter.html">component</a> in versions 8.4+, and provides way higher flexibility and finer-grained control on what and when is logged.</p>
<p>With Audit Log Filter, to minimize noise and overhead, it is possible to log only failed login attempts, so legitimate application sessions won&rsquo;t flood the log.</p>
<p>Here is an example of how to enable such a filter rule:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">mysql&rsaquo; SELECT audit_log_filter_set_filter(
  'failed_logins_only',
  '{
    "filter": {
      "log": false,
      "class": {
        "name": "connection",
        "event": {
          "name": "connect",
          "log": {
            "not": {
              "field": { "name": "status", "value": "0" }
            }
          }
        }
      }
    }
  }'
);
mysql&rsaquo; SELECT audit_log_filter_set_user('%', 'failed_logins_only');</pre>
<p>The above rules set logging for the connection class, for all events that resulted in an error (status is not success).</p>
<p>An example entry for a client trying to authenticate with the wrong user credentials may look like this (if JSON format is used):</p>
<pre class="urvanov-syntax-highlighter-plain-tag">{
    "timestamp": "2026-03-05 11:31:12",
    "id": 8,
    "class": "connection",
    "event": "connect",
    "connection_id": 31,
    "account": { "user": "wronguser", "host": "" },
    "login": { "user": "wronguser", "os": "", "ip": "192.168.121.16", "proxy": "" },
    "connection_data": {
      "connection_type": "ssl",
      "status": 1045,
      "db": ""
    },
    "connection_attributes": {
      "_pid": "3608615",
      "_platform": "x86_64",
      "_os": "Linux",
      "_client_name": "libmysql",
      "os_user": "przemek",
      "_client_version": "8.4.7-7"
    }
  }</pre>
<p>And a simple TCP probe (netcat) may look like this:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">{
    "timestamp": "2026-03-05 11:31:26",
    "id": 9,
    "class": "connection",
    "event": "connect",
    "connection_id": 32,
    "account": { "user": "", "host": "test-host1" },
    "login": { "user": "", "os": "", "ip": "192.168.46.13", "proxy": "" },
    "connection_data": {
      "connection_type": "tcp/ip",
      "status": 1158,
      "db": ""
    }
  }</pre>
<p>Unfortunately, again, connections from unknown hosts are not logged. Logging attempts aborted early on the host validation phase, do not reach the audit log or any other log! This is because <a href="https://github.com/mysql/mysql-server/blob/trunk/sql/sql_connect.cc#L610C1-L615C16" rel="nofollow">the validation occurs at the very beginning of the handshake workflow</a>, and if it returns failure, the connection is terminated before reaching the logging capabilities.</p>
<p>To workaround this limitation and make all unsuccessful login attempts be logged, we need to create a catch-all user account. However, we don&rsquo;t want to extend the possible attack surface at the same time, so let&rsquo;s disable authentication entirely for such an account. We will need the <a href="https://dev.mysql.com/doc/refman/8.4/en/no-login-pluggable-authentication.html" rel="nofollow">no-login plugin</a> first:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">INSTALL PLUGIN mysql_no_login SONAME 'mysql_no_login.so';</pre>
<p>Now, the following user entry will allow auditing connection attempts from any host/IP:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">CREATE USER ''@'%' IDENTIFIED WITH mysql_no_login;</pre>
<p>Now, specific port knocking may still not be logged, like with nmap, as the client sends a RST packet even before the initial MySQL &ldquo;hello&rdquo; packet. So, we will not see this session anywhere in the MySQL logs:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">$ nmap 192.168.46.20 -sT -p 3306
Starting Nmap 7.94SVN ( https://nmap.org ) at 2026-03-11 07:24 CET
Nmap scan report for 192.168.46.20 (192.168.46.20)
Host is up (0.00021s latency).
PORT     STATE SERVICE
3306/tcp open  mysql
Nmap done: 1 IP address (1 host up) scanned in 0.02 seconds</pre>
<p>The only way to capture the above would be to watch the wire protocol, i.e., with tcpdump.</p>
<h2>Additional Instrumentation<a class="anchor-link" id="additional-instrumentation"></a></h2>
<p>The error log entries can be viewed in a more structured manner, with the P_S table, so the entry:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">2026-02-25T20:46:40.779435Z 66 [Note] [MY-010926] [Server] Access denied for user 'wronguser'@'test-host1' (using password: YES)</pre>
<p>Will have equivalent in:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">mysql&rsaquo; select * from performance_schema.error_log order by LOGGED desc limit 1&#10741;G
*************************** 1. row ***************************
    LOGGED: 2026-02-25 20:46:40.779435
 THREAD_ID: 66
      PRIO: Note
ERROR_CODE: MY-010926
 SUBSYSTEM: Server
      DATA: Access denied for user 'wronguser'@'test-host1' (using password: YES)
1 row in set (0.00 sec)</pre>
<p>And it allows SQL queries against the log, like aggregations:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">mysql&rsaquo; select count(*) from performance_schema.error_log where ERROR_CODE='MY-010926';
+----------+
| count(*) |
+----------+
|       11 |
+----------+
1 row in set (0.00 sec)</pre>
<p>Also, MySQL keeps track of connection attempts from external hosts in the host cache structure, which can be observed via <code><a href="https://dev.mysql.com/doc/refman/8.4/en/performance-schema-host-cache-table.html" rel="nofollow">performance_schema.host_cache</a></code> view. The view provides statistics on the number of failed connections grouped by reason categories, together with success and failure timestamps. This view provides information only about source hosts&rsquo; connection events, but not users. An example output may look like this:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">mysql&rsaquo; select * from performance_schema.host_cache&#10741;G
*************************** 1. row ***************************
                                        IP: 192.168.46.12
                                      HOST: test-host1
                            HOST_VALIDATED: YES
                        SUM_CONNECT_ERRORS: 2
                 COUNT_HOST_BLOCKED_ERRORS: 0
           COUNT_NAMEINFO_TRANSIENT_ERRORS: 0
           COUNT_NAMEINFO_PERMANENT_ERRORS: 0
                       COUNT_FORMAT_ERRORS: 0
           COUNT_ADDRINFO_TRANSIENT_ERRORS: 0
           COUNT_ADDRINFO_PERMANENT_ERRORS: 0
                       COUNT_FCRDNS_ERRORS: 0
                     COUNT_HOST_ACL_ERRORS: 0
               COUNT_NO_AUTH_PLUGIN_ERRORS: 0
                  COUNT_AUTH_PLUGIN_ERRORS: 3
                    COUNT_HANDSHAKE_ERRORS: 2
                   COUNT_PROXY_USER_ERRORS: 0
               COUNT_PROXY_USER_ACL_ERRORS: 0
               COUNT_AUTHENTICATION_ERRORS: 5
                          COUNT_SSL_ERRORS: 0
         COUNT_MAX_USER_CONNECTIONS_ERRORS: 0
COUNT_MAX_USER_CONNECTIONS_PER_HOUR_ERRORS: 0
             COUNT_DEFAULT_DATABASE_ERRORS: 2
                 COUNT_INIT_CONNECT_ERRORS: 0
                        COUNT_LOCAL_ERRORS: 0
                      COUNT_UNKNOWN_ERRORS: 0
                                FIRST_SEEN: 2026-02-25 20:41:57
                                 LAST_SEEN: 2026-02-26 09:02:35
                          FIRST_ERROR_SEEN: 2026-02-25 20:42:17
                           LAST_ERROR_SEEN: 2026-02-26 09:02:38
1 row in set (0.00 sec)</pre>
<p>Depending on what was wrong with the connection or authentication attempt, a different counter will increment. For instance, when a user tries to log in with the default database, it does not have the privilege to, the COUNT_DEFAULT_DATABASE_ERRORS will increase. When an unknown user tries to log in without a password, the COUNT_AUTH_PLUGIN_ERRORS is used, but when any user (existing or not) tries a wrong password, the COUNT_AUTHENTICATION_ERRORS gets used instead.</p>
<p>Some cases of port probing, for example, using telnet or netcat, will increment COUNT_HANDSHAKE_ERRORS. Interestingly, though, the nmap probe does not increment any of them.</p>
<p>Also, when there is no catch-all user and no user entry matching the source IP/host/network, the <code>host_cache</code> table will allow us to at least observe statistics about failed logins per source IP, as each connection refused on the host validation phase will increment the <code>COUNT_HOST_ACL_ERRORS</code> counter.</p>
<p>Some limited visibility into failed login attempts can be available via the <a href="https://dev.mysql.com/doc/refman/8.4/en/connection-control-plugin.html" rel="nofollow">Connection Control Plugin</a>. However, this plugin&rsquo;s main purpose is not auditing, but rather slowing down brute force attacks against MySQL user accounts. Still, when installed, failed attempt counts are visible via the following view:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">mysql&rsaquo; select * from information_schema.CONNECTION_CONTROL_FAILED_LOGIN_ATTEMPTS;
+---------------------+-----------------+
| USERHOST            | FAILED_ATTEMPTS |
+---------------------+-----------------+
| ''@'test-host1'     |              10 |
| ''@'192.168.121.13' |               4 |
| 'root'@'localhost'  |               3 |
| ''@'%'              |              10 |
+---------------------+-----------------+
4 rows in set (0.01 sec)</pre>
<p>Finally, another <a href="https://docs.percona.com/percona-server/8.4/additional-performance-schema-tables.html">per-user view</a> was added in recent Percona Server versions, which shows how many failed login attempts are left until the account gets locked. This feature is active (tracking active) only for the accounts that have the <a href="https://dev.mysql.com/doc/refman/8.4/en/password-management.html#failed-login-tracking"><code>FAILED_LOGIN_ATTEMPTS</code> and <code>PASSWORD_LOCK_TIME</code></a> limitations:</p>
<pre class="urvanov-syntax-highlighter-plain-tag">mysql&rsaquo; select * from performance_schema.account_failed_login_lock_status;
+-------------------+-----------+--------------------+--------------+--------------------+-----------+--------------------+-----------------------+
| USER              | HOST      | IS_TRACKING_ACTIVE | MAX_ATTEMPTS | PASSWORD_LOCK_DAYS | IS_LOCKED | REMAINING_ATTEMPTS | REMAINING_DAYS_LOCKED |
+-------------------+-----------+--------------------+--------------+--------------------+-----------+--------------------+-----------------------+
| mysql.infoschema  | localhost | NO                 |            0 |                  0 | NULL      |               NULL |                  NULL |
| mysql.session     | localhost | NO                 |            0 |                  0 | NULL      |               NULL |                  NULL |
| mysql.sys         | localhost | NO                 |            0 |                  0 | NULL      |               NULL |                  NULL |
| percona.telemetry | localhost | NO                 |            0 |                  0 | NULL      |               NULL |                  NULL |
| root              | localhost | NO                 |            0 |                  0 | NULL      |               NULL |                  NULL |
| user1             | %         | YES                |          100 |                  1 | NO        |                 96 |                     0 |
| NULL              | %         | NO                 |            0 |                  0 | NULL      |               NULL |                  NULL |
+-------------------+-----------+--------------------+--------------+--------------------+-----------+--------------------+-----------------------+
7 rows in set (0.00 sec)</pre>

<h3>Summary<a class="anchor-link" id="summary"></a></h3>
<p>There are multiple ways to monitor MySQL or MariaDB login attempts, but only the <a href="https://docs.percona.com/percona-server/8.4/audit-log-filter-overview.html">Audit Log Filter</a> allows you to specify exactly what you want to log, like only failed logins, for instance. Due to MySQL connection handling behavior, in order to log authentication attempts from undefined hosts, a secure catch-all user account may be needed, though.</p>
<p>As for the TCP scanners, MySQL may not be able to log all such connection attempts, depending on how fast the connection is terminated.</p>
<p><em>The article was created by a human.</em></p>
<p>&nbsp;</p>
<p>The post <a href="https://www.percona.com/blog/auditing-login-attempts-in-mysql-and-mariadb/">Auditing Login Attempts in MySQL and MariaDB</a> appeared first on <a href="https://www.percona.com">Percona</a>.</p>

<p>The post <a rel="nofollow" href="https://www.percona.com/blog/auditing-login-attempts-in-mysql-and-mariadb/">Auditing Login Attempts in MySQL and MariaDB</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>MariaDB Foundation releases the BETA of the Test Automation Framework (TAF) 2.5</title>
      <link>https://mariadb.org/mariadb-foundation-releases-the-beta-of-the-test-automation-framework-taf-2-5/</link>
      <pubDate>Sun, 12 Apr 2026 13:39:48 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.org/">MariaDB.org</source>
      <description><![CDATA[<p>The MariaDB Foundation is releasing the BETA version of the Test Automation Framework (TAF) 2.5. This release represents a significant architectural upgrade, strengthening the framework’s lifecycle model, profiling capabilities, extraction and install pipeline, and reporting consistency. …<br />
Continue reading \"MariaDB Foundation releases the BETA of the Test Automation Framework (TAF) 2.5\"<br />
The post MariaDB Foundation releases the BETA of the Test Automation Framework (TAF) 2.5 appeared first on MariaDB.org.</p>
<p>The post <a rel="nofollow" href="https://mariadb.org/mariadb-foundation-releases-the-beta-of-the-test-automation-framework-taf-2-5/">MariaDB Foundation releases the BETA of the Test Automation Framework (TAF) 2.5</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>The MariaDB Foundation is releasing the BETA version of the Test Automation Framework (TAF) 2.5. This release represents a significant architectural upgrade, strengthening the framework&rsquo;s lifecycle model, profiling capabilities, extraction and install pipeline, and reporting consistency. &hellip; </p>
<p class="link-more"><a href="https://mariadb.org/mariadb-foundation-releases-the-beta-of-the-test-automation-framework-taf-2-5/" class="more-link">Continue reading<span class="screen-reader-text"> &ldquo;MariaDB Foundation releases the BETA of the Test Automation Framework (TAF) 2.5&rdquo;</span></a></p>
<p>The post <a rel="nofollow" href="https://mariadb.org/mariadb-foundation-releases-the-beta-of-the-test-automation-framework-taf-2-5/">MariaDB Foundation releases the BETA of the Test Automation Framework (TAF) 2.5</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>

<p>The post <a rel="nofollow" href="https://mariadb.org/mariadb-foundation-releases-the-beta-of-the-test-automation-framework-taf-2-5/">MariaDB Foundation releases the BETA of the Test Automation Framework (TAF) 2.5</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>What Our Survey Says About MariaDB Preview Releases</title>
      <link>https://mariadb.org/what-our-survey-says-about-mariadb-preview-releases/</link>
      <pubDate>Fri, 10 Apr 2026 07:33:17 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.org/">MariaDB.org</source>
      <description><![CDATA[<p>Preview releases are among the clearest ways an open-source community can shape the future of a database before it becomes a production reality. They give users early access to new features, a chance to validate upgrade paths, and an opportunity to catch issues while the change is still inexpensive. …<br />
Continue reading \"What Our Survey Says About MariaDB Preview Releases\"<br />
The post What Our Survey Says About MariaDB Preview Releases appeared first on MariaDB.org.</p>
<p>The post <a rel="nofollow" href="https://mariadb.org/what-our-survey-says-about-mariadb-preview-releases/">What Our Survey Says About MariaDB Preview Releases</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>Preview releases are among the clearest ways an open-source community can shape the future of a database before it becomes a production reality. They give users early access to new features, a chance to validate upgrade paths, and an opportunity to catch issues while the change is still inexpensive. &hellip; </p>
<p class="link-more"><a href="https://mariadb.org/what-our-survey-says-about-mariadb-preview-releases/" class="more-link">Continue reading<span class="screen-reader-text"> &ldquo;What Our Survey Says About MariaDB Preview Releases&rdquo;</span></a></p>
<p>The post <a rel="nofollow" href="https://mariadb.org/what-our-survey-says-about-mariadb-preview-releases/">What Our Survey Says About MariaDB Preview Releases</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>

<p>The post <a rel="nofollow" href="https://mariadb.org/what-our-survey-says-about-mariadb-preview-releases/">What Our Survey Says About MariaDB Preview Releases</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>MariaDB Vector: How it works. Part IV</title>
      <link>https://mariadb.org/mariadb-vector-how-it-works-part-iv/</link>
      <pubDate>Thu, 09 Apr 2026 06:42:55 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.org/">MariaDB.org</source>
      <description><![CDATA[<p>This is the last post in the “MariaDB Vector: How it works” series. The first three were about storage, in-memory representation, HNSW modifications. …<br />
Continue reading \"MariaDB Vector: How it works. Part IV\"<br />
The post MariaDB Vector: How it works. Part IV appeared first on MariaDB.org.</p>
<p>The post <a rel="nofollow" href="https://mariadb.org/mariadb-vector-how-it-works-part-iv/">MariaDB Vector: How it works. Part IV</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>This is the last post in the &ldquo;MariaDB Vector: How it works&rdquo; series. The first three were about <a href="https://mariadb.org/mariadb-vector-how-it-works/" target="_blank" rel="noreferrer noopener">storage</a>, <a href="https://mariadb.org/mariadb-vector-how-it-works-part-ii/" target="_blank" rel="noreferrer noopener">in-memory representation</a>, <a href="https://mariadb.org/mariadb-vector-how-it-works-part-iii/" target="_blank" rel="noreferrer noopener">HNSW modifications</a>. &hellip; </p>
<p class="link-more"><a href="https://mariadb.org/mariadb-vector-how-it-works-part-iv/" class="more-link">Continue reading<span class="screen-reader-text"> &ldquo;MariaDB Vector: How it works. Part IV&rdquo;</span></a></p>
<p>The post <a rel="nofollow" href="https://mariadb.org/mariadb-vector-how-it-works-part-iv/">MariaDB Vector: How it works. Part IV</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>

<p>The post <a rel="nofollow" href="https://mariadb.org/mariadb-vector-how-it-works-part-iv/">MariaDB Vector: How it works. Part IV</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Percona ClusterSync for MongoDB 0.8.0: Up to 18x Faster Change Replication</title>
      <link>https://www.percona.com/blog/percona-clustersync-for-mongodb-0-8-0-up-to-18x-faster-change-replication/</link>
      <pubDate>Tue, 07 Apr 2026 22:00:05 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://goat.percona.com/blog/">Blog - Percona</source>
      <description><![CDATA[<p>Percona ClusterSync for MongoDB (PCSM) replicates data between MongoDB clusters — whether replica sets or sharded — handling both the initial bulk data clone and continuous change replication via MongoDB’s change streams. It’s designed for migrations, failover preparation, and keeping a secondary cluster in sync with production. Version 0.8.0 brings two architectural changes to the … Continued<br />
The post Percona ClusterSync for MongoDB 0.8.0: Up to 18x Faster Change Replication appeared first on Percona.</p>
<p>The post <a rel="nofollow" href="https://www.percona.com/blog/percona-clustersync-for-mongodb-0-8-0-up-to-18x-faster-change-replication/">Percona ClusterSync for MongoDB 0.8.0: Up to 18x Faster Change Replication</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p><span style="font-weight: 400">Percona ClusterSync for MongoDB (PCSM) replicates data between MongoDB clusters &mdash; whether replica sets or sharded &mdash; handling both the initial bulk data clone and continuous change replication via MongoDB&rsquo;s change streams. It&rsquo;s designed for migrations, failover preparation, and keeping a secondary cluster in sync with production.</span></p>
<p><a href="https://docs.percona.com/percona-clustersync-for-mongodb/release-notes/0.8.0.html"><span style="font-weight: 400">Version 0.8.0</span></a><span style="font-weight: 400"> brings two architectural changes to the change replication pipeline that significantly improve throughput and reduce replication lag under high write workloads. Both changes target the continuous replication phase &mdash; the long-running process that tails the source cluster&rsquo;s change stream and applies events to the target.</span></p>
<p><span style="font-weight: 400">In this post, we&rsquo;ll walk through what changed, why it matters, and how the new architecture works.</span></p>
<h1><b>The Starting Point: A Simple, Correct Pipeline</b><a class="anchor-link" id="the-starting-point-a-simple-correct-pipeline"></a></h1>
<p><span style="font-weight: 400">The original change replication pipeline in PCSM was intentionally simple. A single goroutine handled the entire flow: reading events from the MongoDB change stream, parsing the BSON payloads, and writing bulk operations to the target cluster &mdash; all sequentially, in a single thread.</span></p>
<p><span style="font-weight: 400">This design was a deliberate choice. Replicating data between MongoDB clusters involves subtle correctness challenges &mdash; preserving document-level operation ordering, handling DDL events that affect schema, and maintaining checkpoint consistency so replication can resume safely after a failure. Getting all of this right was the priority, and a single-threaded pipeline made the logic easier to reason about, test, and verify.&nbsp;</span></p>
<p><span style="font-weight: 400">The trade-off was performance. Under high write throughput, the sequential pipeline became a bottleneck. While the worker waited for MongoDB to acknowledge a bulk write, it couldn&rsquo;t read new events from the change stream. Write latency on the target directly blocked read throughput from the source. Replication lag would grow under sustained load, even when both clusters had spare capacity.</span></p>
<p><span style="font-weight: 400">With the correctness foundation proven across months of testing and production use than </span><a href="https://docs.percona.com/percona-clustersync-for-mongodb/release-notes/0.7.0.html"><span style="font-weight: 400">adding support for sharded clusters in 0.7.0</span></a><span style="font-weight: 400">,&nbsp; 0.8.0 was the right time to unlock performance &mdash; without compromising those guarantees.</span></p>
<h1><b>Feature 1: Document-Level Parallel Replication</b><a class="anchor-link" id="feature-1-document-level-parallel-replication"></a></h1>
<p><span style="font-weight: 400">The first major change replaces the single-goroutine pipeline with a worker pool architecture that processes events in parallel across multiple workers.</span></p>
<h2><b>How It Works</b><a class="anchor-link" id="how-it-works"></a></h2>
<p><span style="font-weight: 400">The pipeline is now split into three stages:</span></p>
<p><img decoding="async" loading="lazy" class="size-full wp-image-43369 aligncenter" src="https://www.percona.com/wp-content/uploads/2026/04/PCSM-0.8.0-Diagram-1-1024x406-1.png" alt="" width="1024" height="406"></p>
<ul>
<li><b>Reader</b><span style="font-weight: 400"> &mdash; A single goroutine reads events from the MongoDB change stream. Instead of parsing and applying them immediately, it passes the raw BSON downstream.</span></li>
<li><b>Dispatcher</b><span style="font-weight: 400"> &mdash; Routes each event to a specific worker based on a consistent hash of the document key. This is the critical design decision: the same document always maps to the same worker, which preserves per-document operation ordering without any cross-worker coordination.</span></li>
<li><b>Workers</b><span style="font-weight: 400"> &mdash; Each worker independently parses BSON and builds bulk write operations for its assigned documents. By default, the number of workers matches the number of available CPU cores.</span></li>
</ul>
<h2><b>Preserving Correctness</b><a class="anchor-link" id="preserving-correctness"></a></h2>
<p><span style="font-weight: 400">Parallelism introduces risk if you&rsquo;re not careful. PCSM 0.8.0 handles the edge cases:</span></p>
<ul>
<li><b>Per-document ordering</b><span style="font-weight: 400"> is guaranteed by the hashing scheme &mdash; all operations for a given document flow through the same worker, in order. This way, we ensure we don&rsquo;t insert a document after it was deleted.</span></li>
<li><b>DDL events</b><span style="font-weight: 400"> (collection drops, renames, index changes) trigger a </span><b><i>write barrier</i></b><span style="font-weight: 400">: All workers flush their pending writes before the DDL is applied, then resume. This prevents schema changes from racing with in-flight DML operations. Essentially ensures we don&rsquo;t insert documents into a collection that was dropped in the meantime.</span></li>
<li><b>Capped collections</b><span style="font-weight: 400"> are routed by namespace rather than document key, that way all the documents from capped collections are routed to the same worker, preserving insertion order as MongoDB requires.</span></li>
</ul>
<h2><b>Deferred Parsing</b><a class="anchor-link" id="deferred-parsing"></a></h2>
<p><span style="font-weight: 400">A secondary but meaningful optimization: BSON parsing now happens inside the workers rather than in the reader. In the old pipeline, the single goroutine parsed every event before doing anything else. Now, raw BSON is passed to N workers, which parse it in parallel. This spreads CPU-bound work across cores and keeps the reader focused on consuming events from the change stream as fast as possible.</span></p>
<h1><b>Feature 2: Async Bulk Write Pipeline</b><a class="anchor-link" id="feature-2-async-bulk-write-pipeline"></a></h1>
<p><span style="font-weight: 400">The second change goes one level deeper. Even with multiple workers, each worker still had the original problem: when it called </span><span style="font-weight: 400">flush()</span><span style="font-weight: 400"> to write a bulk operation to MongoDB, it blocked until the write was acknowledged. During that time, the worker couldn&rsquo;t read new events from its queue.</span></p>
<p><span style="font-weight: 400">The async bulk-write pipeline decouples bulk building from bulk writing within each worker.</span></p>
<h2><b>How It Works</b><a class="anchor-link" id="how-it-works"></a></h2>
<p><span style="font-weight: 400">Each worker now has two goroutines:</span></p>
<p><img decoding="async" loading="lazy" class="size-full wp-image-43368 aligncenter" src="https://www.percona.com/wp-content/uploads/2026/04/PCSM-0.8.0-Diagram-2-1024x305-1.png" alt="" width="1024" height="305"></p>
<ul>
<li><b>Main loop</b><span style="font-weight: 400"> &mdash; Reads events from its queue, parses BSON, and assembles bulk write operations. When a bulk is full (or the flush interval fires), it seals the bulk and submits it to a bounded queue. After the sealed bulk is queued, the loop continues processing events and building the next bulk without waiting.</span></li>
<li><b>Async writer</b><span style="font-weight: 400"> &mdash; A dedicated goroutine that dequeues sealed bulks and executes them against MongoDB. While a write is in-flight, the main loop continues building the next batch.</span></li>
</ul>
<p><span style="font-weight: 400">This means workers are never idle waiting for MongoDB. They&rsquo;re always reading and batching the next set of operations while the previous write completes.</span></p>
<h2><b>Backpressure and Memory Bounds</b><a class="anchor-link" id="backpressure-and-memory-bounds"></a></h2>
<p><span style="font-weight: 400">The bulk queue per worker is bounded (default size: 3). When the queue is full, the main loop blocks on <code>submit()</code> until the writer dequeues a bulk. This provides natural backpressure &mdash; if MongoDB can&rsquo;t keep up, workers slow down rather than consuming unbounded memory.</span></p>
<p><span style="font-weight: 400">Maximum memory per worker is capped at: workers event queue size + bulk batches queue size + 1 bulk being written + 1 bulk being built. This is predictable and configurable.</span></p>
<h2><b>Checkpoint Safety</b><a class="anchor-link" id="checkpoint-safety"></a></h2>
<p><span style="font-weight: 400">Each sealed bulk captures the checkpoint timestamp at seal time &mdash; the timestamp of the latest event included in that bulk. The committed checkpoint is only advanced after the async writer confirms the bulk was persisted to MongoDB. This ensures that if PCSM crashes or restarts, it resumes from a timestamp that reflects what was actually written, never skipping events.</span></p>
<h2><b>Barrier Handling</b><a class="anchor-link" id="barrier-handling"></a></h2>
<p><span style="font-weight: 400">When a barrier event arrives (DDL or stop request), the main loop closes the bulk queue and waits for the async writer to finish all pending bulks. Only after everything is flushed does the barrier proceed. On resume, the writer goroutine is restarted with fresh state.</span></p>
<h1><b>The Combined Effect</b><a class="anchor-link" id="the-combined-effect"></a></h1>
<p><span style="font-weight: 400">Together, these two features transform the pipeline from a single-threaded sequential process into a fully pipelined, parallel architecture:</span></p>
<p><img decoding="async" loading="lazy" class="size-full wp-image-43367 aligncenter" src="https://www.percona.com/wp-content/uploads/2026/04/PCSM-0.8.0-Diagram-3-1024x363-1.png" alt="" width="1024" height="363"></p>
<p><span style="font-weight: 400">The improvement is multiplicative:</span></p>
<ul>
<li><b>Parallel replication</b><span style="font-weight: 400"> spreads work across N workers (CPU cores).</span></li>
<li><b>Async writes</b><span style="font-weight: 400"> ensure each worker overlaps I/O with computation, eliminating idle time waiting for MongoDB acknowledgments.</span></li>
</ul>
<p><span style="font-weight: 400">The result is that the pipeline can sustain substantially higher event throughput before replication lag begins to grow.</span></p>
<h2><b>Tuning options</b><a class="anchor-link" id="tuning-options"></a></h2>
<p><span style="font-weight: 400">All replication tuning parameters (worker count, queue sizes, batch sizes, flush intervals) are now configurable via CLI flags, environment variables, and the HTTP API. The defaults are auto-tuned and work well for most deployments. For the full list of options and guidance on when to adjust them, see the </span><a href="https://docs.percona.com/percona-clustersync-for-mongodb/pcsm-commands.html#start"><span style="font-weight: 400">PCSM Configuration Reference</span></a><span style="font-weight: 400">.</span></p>
<h1><b>Benchmark Results</b><a class="anchor-link" id="benchmark-results"></a></h1>
<p><span style="font-weight: 400">We tested change replication throughput across document sizes ranging from 500 bytes to 200 KB. Source client compressors set for maximizing change stream read throughput. The metric is maximum sustained QPS (queries per second on the source) before replication lag begins to accumulate.</span></p>
<p><span style="font-weight: 400">PCSM was running on an AWS i3en.3xlarge</span> <span style="font-weight: 400">instance with 12 CPU cores and 96 GiB of RAM.</span></p>
<p><b>Replica Set Clusters Test Results</b></p>
<p><img decoding="async" loading="lazy" class="size-full wp-image-43366 aligncenter" src="https://www.percona.com/wp-content/uploads/2026/04/RS-test-results-1024x633-1.png" alt="" width="1024" height="633"></p>
<p><span style="font-weight: 400">From the graph we can see that we have </span><b>4.5x</b><span style="font-weight: 400"> improvement for small, </span><b>4.2x</b><span style="font-weight: 400"> for regular and</span><b> 3.1x</b><span style="font-weight: 400"> for big documents.</span></p>
<p><b>Sharded Cluster Test Results</b></p>
<p><img decoding="async" loading="lazy" class="size-full wp-image-43365 aligncenter" src="https://www.percona.com/wp-content/uploads/2026/04/Sharded-tests-results-1024x633-1.png" alt="" width="1024" height="633"></p>
<p><span style="font-weight: 400">On sharded clusters we can see much bigger improvements, that is </span><b>14,5x</b><span style="font-weight: 400"> for small,&nbsp; </span><b>18,5x </b><span style="font-weight: 400">for regular and </span><b>6x</b><span style="font-weight: 400"> improvement for big documents.</span></p>
<h1><b>What&rsquo;s Next</b><a class="anchor-link" id="whats-next"></a></h1>
<p><span style="font-weight: 400">PCSM 0.8.0 removes the major bottleneck that existed during the apply phase &mdash; parsing events and writing them to the target. With parallel workers and async writes, the apply pipeline can now saturate the target cluster&rsquo;s write capacity much more effectively.</span></p>
<p><span style="font-weight: 400">Interestingly, this shifts the bottleneck. In our testing, the primary limiting factor is now the rate at which events can be read from MongoDB&rsquo;s change stream, particularly when documents are large. Change stream throughput is ultimately governed by MongoDB server-side performance and network bandwidth, which are outside PCSM&rsquo;s control. This is an area we&rsquo;re actively investigating for future releases.</span></p>
<p><span style="font-weight: 400">For sharded clusters, we plan to add support for multi-instance PCSM deployment, where each PCSM instance handles a single shard independently. This will allow replication throughput to scale linearly with the number of shards.</span></p>
<p><span style="font-weight: 400">If you&rsquo;re evaluating PCSM for a migration or considering an upgrade, 0.8.0 is a significant step forward for write-heavy workloads. The defaults are designed to work well without tuning, but the new configuration options give you full control when you need it.</span></p>
<h1><b>Join the Community</b><a class="anchor-link" id="join-the-community"></a></h1>
<p><span style="font-weight: 400">Percona thrives on community collaboration. As we continue to refine PCSM and celebrate its production-ready GA release, we invite you to get involved. We welcome bug reports, feature suggestions, and code contributions. Your input helps us build the tools the MongoDB community actually needs. We encourage you to deploy PCSM in your production environments today! Check out the </span><a href="https://github.com/percona/percona-clustersync-mongodb"><span style="font-weight: 400">PCSM repository</span></a><span style="font-weight: 400"> and join the journey with us!</span></p>
<p><b>Ready to break free from vendor lock-in?</b><span style="font-weight: 400"> Check out the</span><a href="https://docs.percona.com/percona-clustersync-for-mongodb/"> <span style="font-weight: 400">PCSM Documentation</span></a><span style="font-weight: 400"> to get started with your first sync today.</span></p>
<p>The post <a href="https://www.percona.com/blog/percona-clustersync-for-mongodb-0-8-0-up-to-18x-faster-change-replication/">Percona ClusterSync for MongoDB 0.8.0: Up to 18x Faster Change Replication</a> appeared first on <a href="https://www.percona.com">Percona</a>.</p>

<p>The post <a rel="nofollow" href="https://www.percona.com/blog/percona-clustersync-for-mongodb-0-8-0-up-to-18x-faster-change-replication/">Percona ClusterSync for MongoDB 0.8.0: Up to 18x Faster Change Replication</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>The AWS Lambda ‘Kiss of Death’</title>
      <link>https://shatteredsilicon.net/the-aws-lambda-kiss-of-death/</link>
      <pubDate>Tue, 07 Apr 2026 18:15:28 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://shatteredsilicon.net/wp-json/;%20rel=https://api.w.org/,%20https://shatteredsilicon.net/wp-json/wp/v2/categories/17;%20type=application/json,%20https://shatteredsilicon.net/category/databases-mysql-mariadb-postgresql/;%20rel=canonical">Databases (MySQL, MariaDB, PostgreSQL) Archives - Shattered Silicon</source>
      <description><![CDATA[<p>Our story begins as most database issues start: with hands on foreheads, internally or externally, saying ‘WTF is going on?’. We observed a series of database freezes on our production environment. It was quite severe. Connections spiked, writes were stalled and at some point, a large database freeze and they cleared. Being a Galera environment, […]<br />
The post The AWS Lambda ‘Kiss of Death’ appeared first on Shattered Silicon.</p>
<p>The post <a rel="nofollow" href="https://shatteredsilicon.net/the-aws-lambda-kiss-of-death/">The AWS Lambda ‘Kiss of Death’</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>Our story begins as most database issues start: with hands on foreheads, internally or externally, saying &lsquo;WTF is going on?&rsquo;. We observed a series of database freezes on our production environment. It was quite severe. Connections spiked, writes were stalled and at some point, a large database freeze and they cleared. Being a Galera environment, [&hellip;]</p>
<p>The post <a rel="nofollow" href="https://shatteredsilicon.net/the-aws-lambda-kiss-of-death/">The AWS Lambda &lsquo;Kiss of Death&rsquo;</a> appeared first on <a rel="nofollow" href="https://shatteredsilicon.net">Shattered Silicon</a>.</p>

<p>The post <a rel="nofollow" href="https://shatteredsilicon.net/the-aws-lambda-kiss-of-death/">The AWS Lambda ‘Kiss of Death’</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>The AWS Lambda ‘Kiss of Death’</title>
      <link>https://shatteredsilicon.net/aws-lambda-kiss-of-death/</link>
      <pubDate>Tue, 07 Apr 2026 18:15:28 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://shatteredsilicon.net/wp-json/;%20rel=https://api.w.org/,%20https://shatteredsilicon.net/wp-json/wp/v2/categories/17;%20type=application/json,%20https://shatteredsilicon.net/category/databases-mysql-mariadb-postgresql/;%20rel=canonical">Databases (MySQL, MariaDB, PostgreSQL) Archives - Shattered Silicon</source>
      <description><![CDATA[<p>Our story begins as most database issues start: with hands on foreheads, internally or externally, saying ‘WTF is going on?’. We observed a series of database freezes on our production environment. It was quite severe. Connections spiked, writes were stalled and at some point, a large database freeze and they cleared. Being a Galera environment, […]<br />
The post The AWS Lambda ‘Kiss of Death’ appeared first on Shattered Silicon.</p>
<p>The post <a rel="nofollow" href="https://shatteredsilicon.net/aws-lambda-kiss-of-death/">The AWS Lambda ‘Kiss of Death’</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>Our story begins as most database issues start: with hands on foreheads, internally or externally, saying &lsquo;WTF is going on?&rsquo;. We observed a series of database freezes on our production environment. It was quite severe. Connections spiked, writes were stalled and at some point, a large database freeze and they cleared. Being a Galera environment, [&hellip;]</p>
<p>The post <a rel="nofollow" href="https://shatteredsilicon.net/aws-lambda-kiss-of-death/">The AWS Lambda &lsquo;Kiss of Death&rsquo;</a> appeared first on <a rel="nofollow" href="https://shatteredsilicon.net">Shattered Silicon</a>.</p>

<p>The post <a rel="nofollow" href="https://shatteredsilicon.net/aws-lambda-kiss-of-death/">The AWS Lambda ‘Kiss of Death’</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>A response to Percona’s 2026 MySQL ecosystem benchmark: useful data, but not a realistic MariaDB comparison</title>
      <link>https://mariadb.org/a-response-to-perconas-2026-mysql-ecosystem-benchmark-useful-data-but-not-a-realistic-mariadb-comparison/</link>
      <pubDate>Fri, 03 Apr 2026 07:35:32 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.org/">MariaDB.org</source>
      <description><![CDATA[<p>Percona’s new 2026 benchmark report is interesting because it puts several MySQL-family releases on the same graphs and shares a public repository for the test harness. …<br />
Continue reading \"A response to Percona’s 2026 MySQL ecosystem benchmark: useful data, but not a realistic MariaDB comparison\"<br />
The post A response to Percona’s 2026 MySQL ecosystem benchmark: useful data, but not a realistic MariaDB comparison appeared first on MariaDB.org.</p>
<p>The post <a rel="nofollow" href="https://mariadb.org/a-response-to-perconas-2026-mysql-ecosystem-benchmark-useful-data-but-not-a-realistic-mariadb-comparison/">A response to Percona’s 2026 MySQL ecosystem benchmark: useful data, but not a realistic MariaDB comparison</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p><a href="https://www.percona.com/blog/2026-mysql-ecosystem-performance-benchmark-report/">Percona&rsquo;s new 2026 benchmark report</a> is interesting because it puts several MySQL-family releases on the same graphs and shares a public repository for the test harness. &hellip; </p>
<p class="link-more"><a href="https://mariadb.org/a-response-to-perconas-2026-mysql-ecosystem-benchmark-useful-data-but-not-a-realistic-mariadb-comparison/" class="more-link">Continue reading<span class="screen-reader-text"> &ldquo;A response to Percona&rsquo;s 2026 MySQL ecosystem benchmark: useful data, but not a realistic MariaDB comparison&rdquo;</span></a></p>
<p>The post <a rel="nofollow" href="https://mariadb.org/a-response-to-perconas-2026-mysql-ecosystem-benchmark-useful-data-but-not-a-realistic-mariadb-comparison/">A response to Percona&rsquo;s 2026 MySQL ecosystem benchmark: useful data, but not a realistic MariaDB comparison</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>

<p>The post <a rel="nofollow" href="https://mariadb.org/a-response-to-perconas-2026-mysql-ecosystem-benchmark-useful-data-but-not-a-realistic-mariadb-comparison/">A response to Percona’s 2026 MySQL ecosystem benchmark: useful data, but not a realistic MariaDB comparison</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Percona Bug Report: March 2026</title>
      <link>https://percona.community/blog/2026/04/03/percona-bug-report-march-2026/</link>
      <pubDate>Fri, 03 Apr 2026 00:00:00 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://percona.community/blog/">Percona Community Blog - learn about MySQL, MariaDB, PostgreSQL, and MongoDB</source>
      <description><![CDATA[<p>At Percona, we operate on the premise that full transparency makes a product better. We strive to build the best open-source database products, but also to help you manage any issues that arise in any of the databases that we support. And, in true open-source form, report back on any issues or bugs you might encounter along the way.</p>
<p>The post <a rel="nofollow" href="https://percona.community/blog/2026/04/03/percona-bug-report-march-2026/">Percona Bug Report: March 2026</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>At Percona, we operate on the premise that full transparency makes a product better. We strive to build the best open-source database products, but also to help you manage any issues that arise in any of the databases that we support. And, in true open-source form, report back on any issues or bugs you might encounter along the way.</p>
<p>We constantly update our <a href="https://perconadev.atlassian.net/" target="_blank" rel="noopener noreferrer">bug reports</a> and monitor <a href="https://bugs.mysql.com/" target="_blank" rel="noopener noreferrer">other boards</a> to ensure we have the latest information, but we wanted to make it a little easier for you to keep track of the most critical ones. This post is a central place to get information on the most noteworthy open and recently resolved bugs.</p>
<p>In this edition of our bug report, we have the following list of bugs.</p>
<hr>
<h2 id="percona-servermysql-bugs">Percona Server/MySQL Bugs<a class="anchor-link" id="percona-server-mysql-bugs"></a></h2>
<p><a href="https://perconadev.atlassian.net/browse/PS-10378" target="_blank" rel="noopener noreferrer">PS-10378</a>: In the MeCab plugin, BOOLEAN MODE full-text queries with a LIMIT clause do not behave as expected. Although the optimizer indicates that ranking should be skipped (Ft_hints: no_ranking), the query still performs full ranking and sorting before applying LIMIT, preventing the intended optimization and impacting performance.</p>
<p><strong>Reported Affected Version/s</strong>: 8.4.x<br>
<strong>Upstream Bug</strong>: Not applicable<br>
<strong>Workaround/Fix</strong>: No workaround available<br>
<strong>Fixed/Planned Version/s</strong>: 8.0.46-37, 8.4.9-9, 9.7.0-0</p>
<hr>
<p><a href="https://perconadev.atlassian.net/browse/PS-10448" target="_blank" rel="noopener noreferrer">PS-10448</a>: Insert prepared statements fail on partitioned tables with timestamp-based partitions when the partition key uses a non-constant default (e.g., <strong>CURRENT_TIMESTAMP</strong>). After initial execution, the statement remains bound to the original partition and fails with a partition mismatch error when data should go into a different partition.</p>
<p><strong>Reported Affected Version/s</strong>: 8.0.42-33, 8.0.43-34, 8.0.44-35, 8.4.7-7<br>
<strong>Upstream Bug</strong>: <a href="https://bugs.mysql.com/bug.php?id=119309" target="_blank" rel="noopener noreferrer">Bug #119309</a><br>
<strong>Workaround/Fix</strong>: Modify statements to explicitly use <strong>NOW()</strong> (requires updating procedures)<br>
<strong>Fixed/Planned Version/s</strong>: 8.0.46-37, 8.4.9-9, 9.7.0-0</p>
<hr>
<p><a href="https://perconadev.atlassian.net/browse/PS-10481" target="_blank" rel="noopener noreferrer">PS-10481</a>: The range optimizer incorrectly falls back to a full table scan instead of using an index range scan for WHERE &hellip; IN() queries when values exceed column or prefix length on non-binary collations (e.g. utf8mb4_0900_ai_ci). A single truncated value in IN() can invalidate all valid ranges, forcing a full scan and degrading performance.</p>
<p><strong>Reported Affected Version/s</strong>: 8.4.x<br>
<strong>Upstream Bug</strong>: <a href="https://bugs.mysql.com/bug.php?id=118009" target="_blank" rel="noopener noreferrer">Bug #118009</a><br>
<strong>Workaround/Fix</strong>: No workaround available<br>
<strong>Fixed/Planned Version/s</strong>: Not fixed yet</p>
<hr>
<p><a href="https://perconadev.atlassian.net/browse/PS-10593" target="_blank" rel="noopener noreferrer">PS-10593</a>: The audit_log plugin can crash (segfault) during memcpy operations when configured with audit_log_strategy=PERFORMANCE, audit_log_policy=ALL, and buffering enabled. The issue can be reproduced under specific memory allocator setups (e.g., jemalloc) and also occurs with standard libc malloc, indicating instability in the plugin&rsquo;s memory handling.</p>
<p><strong>Reported Affected Version/s</strong>: 8.0.34-26, 8.0.45-36, 8.4.7-7<br>
<strong>Upstream Bug</strong>: Not applicable<br>
<strong>Workaround/Fix</strong>: No workaround available<br>
<strong>Fixed/Planned Version/s</strong>: 8.0.46-37, 8.4.9-9</p>
<hr>
<p><a href="https://perconadev.atlassian.net/browse/PS-10990" target="_blank" rel="noopener noreferrer">PS-10990</a>: Server crashes (signal 11) in Item_cache::walk when executing queries that use JOIN with a subquery in an IN clause inside stored procedures. The issue occurs during query execution/privilege checking and is reproducible across MySQL and Percona Server 8.0.x versions.</p>
<p><strong>Reported Affected Version/s</strong>: 8.0.45-36<br>
<strong>Upstream Bug</strong>: <a href="https://bugs.mysql.com/bug.php?id=115885" target="_blank" rel="noopener noreferrer">Bug #115885</a><br>
<strong>Workaround/Fix</strong>: Execute the query outside the stored procedure<br>
<strong>Fixed/Planned Version/s</strong>: Not specified</p>
<hr>
<p><a href="https://perconadev.atlassian.net/browse/PS-10578" target="_blank" rel="noopener noreferrer">PS-10578</a>: The legacy audit_log plugin does not populate the DB field in audit records unless the session is started with the &ndash;database option. Even when a database is selected later using USE or referenced explicitly in queries, the DB field may remain empty.</p>
<p><strong>Reported Affected Version/s</strong>: 8.0.43-34, 8.0.45-36<br>
<strong>Upstream Bug</strong>: Not applicable<br>
<strong>Workaround/Fix</strong>: Use Audit Log Filter component (8.4) or audit log filter (8.0), where this issue is not reproducible<br>
<strong>Fixed/Planned Version/s</strong>: Not planned to be fixed</p>
<hr>
<h2 id="percona-xtradb-cluster">Percona Xtradb Cluster<a class="anchor-link" id="percona-xtradb-cluster"></a></h2>
<p><a href="https://perconadev.atlassian.net/browse/PXC-4844" target="_blank" rel="noopener noreferrer">PXC-4844</a>: In PXC clusters under high load, inconsistency voting during DDL or DCL operations can trigger an internal deadlock, causing standby nodes to get stuck applying transactions and continuously request FC pause. Although voting completes successfully and no node is expelled, writes remain blocked in wsrep: replicating and certifying write set, effectively stalling the cluster until the affected node is restarted.</p>
<p><strong>Reported Affected Version/s</strong>: 8.0.42<br>
<strong>Upstream Bug</strong>: Not applicable<br>
<strong>Workaround/Fix</strong>: Restart the blocked standby node to restore cluster activity<br>
<strong>Fixed/Planned Version/s</strong>: Not fixed yet</p>
<hr>
<p><a href="https://perconadev.atlassian.net/browse/PXC-4799" target="_blank" rel="noopener noreferrer">PXC-4799</a>: In PXC clusters, when a backup lock (<strong>LOCK INSTANCE FOR BACKUP</strong>) is active and a replicated DDL is pending, executing <strong>FLUSH TABLES WITH READ LOCK</strong> on the same node can trigger a deadlock. This results in an inconsistency vote and causes the node to leave the cluster, disrupting backup operations.</p>
<p><strong>Reported Affected Version/s</strong>: 8.0.42, 8.0.43, 8.4.6<br>
<strong>Upstream Bug</strong>: Not applicable<br>
<strong>Workaround/Fix</strong>: Avoid running DDL operations during backup or use a single backup instance instead of parallel runs<br>
<strong>Fixed/Planned Version/s</strong>: 8.0.46, 8.4.9, 9.7.0</p>
<hr>
<p><a href="https://perconadev.atlassian.net/browse/PXC-4814" target="_blank" rel="noopener noreferrer">PXC-4814</a>: In PXC with <strong>wsrep_OSU_method=&lsquo;RSU&rsquo;</strong>, a failed DDL due to table name case mismatch (e.g., <strong>OPTIMIZE TABLE</strong>) is incorrectly written to the binary log as a successful transaction (<strong>error_code=0</strong>). This results in a GTID being generated for a failed operation, causing GTID inconsistencies across cluster nodes and in replication setups.</p>
<p><strong>Reported Affected Version/s</strong>: 8.0.33-25, 8.0.44, 8.4.6<br>
<strong>Upstream Bug</strong>: Not applicable<br>
<strong>Workaround/Fix</strong>: Validate table name case sensitivity before executing DDL in RSU mode<br>
<strong>Fixed/Planned Version/s</strong>: 8.0.45, 8.4.8, 9.6.0</p>
<hr>
<p><a href="https://perconadev.atlassian.net/browse/PXC-4845" target="_blank" rel="noopener noreferrer">PXC-4845</a>: After an IST failure (e.g., due to network issues), a PXC node may remain running in an inconsistent state instead of restarting, causing the donor and other nodes to become unresponsive. The joiner node gets stuck during state transfer instead of failing cleanly, impacting overall cluster availability.</p>
<p><strong>Reported Affected Version/s</strong>: 8.0.42<br>
<strong>Upstream Bug</strong>: Not applicable<br>
<strong>Workaround/Fix</strong>: No workaround available<br>
<strong>Fixed/Planned Version/s</strong>: 8.0.45, 8.4.8, 9.6.0</p>
<hr>
<p><a href="https://perconadev.atlassian.net/browse/PXC-4849" target="_blank" rel="noopener noreferrer">PXC-4849</a>: A PXC node fails to start after successful SST when <strong>read_only</strong> or <strong>super_read_only</strong> is enabled and event scheduler objects exist on the donor. During initialization, the event scheduler fails to load, causing the node to abort, making it impossible to run read-only nodes with events defined in the cluster.</p>
<p><strong>Reported Affected Version/s</strong>: 8.0.44, 8.4.7<br>
<strong>Upstream Bug</strong>: Not applicable<br>
<strong>Workaround/Fix</strong>: Start the node without read_only, then enable it manually later, or remove events<br>
<strong>Fixed/Planned Version/s</strong>: 8.0.46, 8.4.9, 9.7.0</p>
<hr>
<p><a href="https://perconadev.atlassian.net/browse/PXC-4965" target="_blank" rel="noopener noreferrer">PXC-4965</a>: Passwords containing the <code>'</code> character are incorrectly handled, causing syntax errors during replication (e.g., <strong>SET PASSWORD</strong>) and triggering inconsistency voting that can force a node to leave the cluster.</p>
<p><strong>Reported Affected Version/s</strong>: 8.0.45, 8.4.7<br>
<strong>Upstream Bug</strong>: Not applicable<br>
<strong>Workaround/Fix</strong>: Avoid using <code>'</code> character in passwords<br>
<strong>Fixed/Planned Version/s</strong>: 8.0.46, 8.4.8, 9.6.0</p>
<hr>
<p><a href="https://perconadev.atlassian.net/browse/PXC-5198" target="_blank" rel="noopener noreferrer">PXC-5198</a>: Executing <strong>SELECT &hellip; FOR UPDATE SKIP LOCKED</strong> can trigger InnoDB crashes with fatal errors (e.g., &ldquo;Unknown error code 21: Skip locked records&rdquo;) under concurrent transactional workloads. Instead of returning expected deadlock errors, the query causes mysqld to abort, impacting cluster stability.</p>
<p><strong>Reported Affected Version/s</strong>: 8.0.33-25, 8.0.35-27, 8.0.36-28<br>
<strong>Upstream Bug</strong>: Not applicable<br>
<strong>Workaround/Fix</strong>: Avoid using <strong>SKIP LOCKED</strong> in <strong>SELECT &hellip; FOR UPDATE</strong> queries<br>
<strong>Fixed/Planned Version/s</strong>: 8.0.46, 8.4.8, 9.6.0</p>
<hr>
<h2 id="percona-xtrabackup">Percona XtraBackup<a class="anchor-link" id="percona-xtrabackup"></a></h2>
<p><a href="https://perconadev.atlassian.net/browse/PXB-3543" target="_blank" rel="noopener noreferrer">PXB-3543</a>: Incremental backups in XtraBackup can become significantly slower than full backups on instances with a very large number of small tables, due to excessive CPU usage in memset during incremental processing. This leads to severe performance degradation, with incremental backups taking hours compared to minutes for full backups.</p>
<p><strong>Reported Affected Version/s</strong>: 8.0.35-33, 8.0.35-34<br>
<strong>Upstream Bug</strong>: Not applicable<br>
<strong>Workaround/Fix</strong>: Use full backups instead of incremental backups<br>
<strong>Fixed/Planned Version/s</strong>: 8.0.35-35, 8.4.0-6, 9.6.0-1</p>
<hr>
<p><a href="https://perconadev.atlassian.net/browse/PXB-3667" target="_blank" rel="noopener noreferrer">PXB-3667</a>: Installation of XtraBackup 8.4 fails on RHEL 9&ndash;based systems due to dependency conflicts between percona-xtrabackup-84, perl(DBD::mysql), and incompatible libmysqlclient versions. Percona Server 8.4 provides libmysqlclient.so.24, while required dependencies expect libmysqlclient.so.21, resulting in unresolved package installation errors.</p>
<p><strong>Reported Affected Version/s</strong>: 8.4.0-5<br>
<strong>Upstream Bug</strong>: Not applicable<br>
<strong>Workaround/Fix</strong>: Not specified<br>
<strong>Fixed/Planned Version/s</strong>: Not specified</p>
<hr>
<h2 id="percona-toolkit">Percona Toolkit<a class="anchor-link" id="percona-toolkit"></a></h2>
<p><a href="https://perconadev.atlassian.net/browse/PT-2519" target="_blank" rel="noopener noreferrer">PT-2519</a>: pt-query-digest fails when processing large, slow query logs, repeatedly throwing &ldquo;Argument &ldquo;&rdquo; isn&rsquo;t numeric&rdquo; errors during the aggregate fingerprint stage. The tool retries multiple times but does not complete, resulting in stalled analysis and very slow progress.</p>
<p><strong>Reported Affected Version/s</strong>: 3.7.0, 3.7.1<br>
<strong>Upstream Bug</strong>: Not applicable<br>
<strong>Workaround/Fix</strong>: Not specified<br>
<strong>Fixed/Planned Version/s</strong>: 3.7.3</p>
<hr>
<p><a href="https://perconadev.atlassian.net/browse/PT-2511" target="_blank" rel="noopener noreferrer">PT-2511</a>: pt-summary incorrectly reports that sshd is not running due to an invalid awk expression used to detect the process. The script checks the wrong field in ps output, causing false negatives even when sshd is active.</p>
<p><strong>Reported Affected Version/s</strong>: 3.7.1<br>
<strong>Upstream Bug</strong>: Not applicable<br>
<strong>Workaround/Fix</strong>: Not specified<br>
<strong>Fixed/Planned Version/s</strong>: 3.7.3</p>
<hr>
<p><a href="https://perconadev.atlassian.net/browse/PT-2516" target="_blank" rel="noopener noreferrer">PT-2516</a>: pt-mongodb-index-check fails to detect duplicate indexes (e.g., <code>{a:1}</code> and <code>{a:1, b:1}</code>) and may produce no output, making it unclear whether the tool is functioning or connecting properly.</p>
<p><strong>Reported Affected Version/s</strong>: 3.7.1<br>
<strong>Upstream Bug</strong>: Not applicable<br>
<strong>Workaround/Fix</strong>: Not specified<br>
<strong>Fixed/Planned Version/s</strong>: Not specified</p>
<hr>
<h2 id="pmm-percona-monitoring-and-management">PMM [Percona Monitoring and Management]<a class="anchor-link" id="pmm-percona-monitoring-and-management"></a></h2>
<p><a href="https://perconadev.atlassian.net/browse/PMM-14493" target="_blank" rel="noopener noreferrer">PMM-14493</a>: PMM fails to start when using Podman with the <strong>&ndash;log-driver passthrough</strong> option due to an error opening /dev/stderr during Nginx initialization. This causes the container to exit with configuration test failure, while other log drivers work as expected.</p>
<p><strong>Reported Affected Version/s</strong>: 3.4.0, 3.4.1<br>
<strong>Upstream Bug</strong>: Not applicable<br>
<strong>Workaround/Fix</strong>: Use a different <strong>&ndash;log-driver</strong> option such as none or journald<br>
<strong>Fixed/Planned Version/s</strong>: 3.8.0</p>
<hr>
<p><a href="https://perconadev.atlassian.net/browse/PMM-14576" target="_blank" rel="noopener noreferrer">PMM-14576</a>: PMM Client reports &ldquo;failed to get backup status&rdquo; errors during MongoDB backups, marking them as failed in the UI even though backups are successfully completed by PBM. This leads to incorrect backup status reporting and confusion for users.</p>
<p><strong>Reported Affected Version/s</strong>: 3.5.0<br>
<strong>Upstream Bug</strong>: Not applicable<br>
<strong>Workaround/Fix</strong>: Avoid using PMM Backup Management (not ideal)<br>
<strong>Fixed/Planned Version/s</strong>: 3.9.0, 3.X</p>
<hr>
<p><a href="https://perconadev.atlassian.net/browse/PMM-14594" target="_blank" rel="noopener noreferrer">PMM-14594</a>: PMM incorrectly reports compatible XtraBackup versions as incompatible with supported MySQL versions during backup validation. This causes backups to be blocked in PMM even when the installed XtraBackup version is the latest available and should be accepted.</p>
<p><strong>Reported Affected Version/s</strong>: 3.5.0, 3.6.0<br>
<strong>Upstream Bug</strong>: Not applicable<br>
<strong>Workaround/Fix</strong>: Use the xtrabackup command-line tool to take backups<br>
<strong>Fixed/Planned Version/s</strong>: 3.9.0</p>
<hr>
<p><a href="https://perconadev.atlassian.net/browse/PMM-14852" target="_blank" rel="noopener noreferrer">PMM-14852</a>: Some panels in the MongoDB InMemory dashboard show no data because they incorrectly use WiredTiger-specific metrics. As a result, dashboards for InMemory storage engine deployments can display empty or misleading panels instead of relevant metrics.</p>
<p><strong>Reported Affected Version/s</strong>: 3.2.0, 3.6.0<br>
<strong>Upstream Bug</strong>: Not applicable<br>
<strong>Workaround/Fix</strong>: Not specified<br>
<strong>Fixed/Planned Version/s</strong>: 3.8.0</p>
<hr>
<p><a href="https://perconadev.atlassian.net/browse/PMM-14906" target="_blank" rel="noopener noreferrer">PMM-14906</a>: The postgres_exporter generates excessive <strong>SELECT version()</strong> queries (~4500/hour) after upgrading to PMM 3.6.0, flooding PostgreSQL logs and increasing unnecessary query load, causing log spam and disk growth.</p>
<p><strong>Reported Affected Version/s</strong>: 3.6.0<br>
<strong>Upstream Bug</strong>: Not applicable<br>
<strong>Workaround/Fix</strong>: Not specified<br>
<strong>Fixed/Planned Version/s</strong>: 3.8.0</p>
<hr>
<p><a href="https://perconadev.atlassian.net/browse/PMM-14958" target="_blank" rel="noopener noreferrer">PMM-14958</a>: mysqld_exporter continues to generate duplicate metric collection errors with GTID and parallel replication enabled, even in PMM 3.6.0. These repeated errors (e.g., <strong>mysql_perf_schema_replication_group_worker_transport_time_seconds</strong>) lead to continuous log spam, causing rapid log growth (up to ~10GB/hour), disk space exhaustion, and increased noise that makes it difficult to identify real issues.</p>
<p><strong>Reported Affected Version/s</strong>: 3.6.0<br>
<strong>Upstream Bug</strong>: Not applicable<br>
<strong>Workaround/Fix</strong>: Not specified<br>
<strong>Fixed/Planned Version/s</strong>: 3.7.1</p>
<hr>
<h2 id="percona-kubernetes-operator">Percona Kubernetes Operator<a class="anchor-link" id="percona-kubernetes-operator"></a></h2>
<p><a href="https://perconadev.atlassian.net/browse/K8SPG-737" target="_blank" rel="noopener noreferrer">K8SPG-737</a>: In PostgreSQL Kubernetes deployments, the node_exporter in the PMM client sidecar cannot access the datadir mountpoint because it is not exposed via /proc, preventing collection of datadir-related metrics. This results in incomplete monitoring data for PostgreSQL pods.</p>
<p><strong>Reported Affected Version/s</strong>: 2.9.0<br>
<strong>Upstream Bug</strong>: Not applicable<br>
<strong>Workaround/Fix</strong>: No workaround available<br>
<strong>Fixed/Planned Version/s</strong>: 2.10.0</p>
<hr>
<p><a href="https://perconadev.atlassian.net/browse/K8SPXC-1737" target="_blank" rel="noopener noreferrer">K8SPXC-1737</a>: The PXC Operator crashes during reconciliation in CompareMySQLVersion when the cluster status lacks a MySQL version value. An empty version field causes a panic (&ldquo;Malformed version&rdquo;), preventing proper cluster reconciliation and replication setup.</p>
<p><strong>Reported Affected Version/s</strong>: 1.18.0, 1.19.0<br>
<strong>Upstream Bug</strong>: Not applicable<br>
<strong>Workaround/Fix</strong>: Create the cluster before configuring replication or manually patch the CR status to include the missing version value, for example:</p>
<div class="code-block">
<div class="code-block__header"><button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-0">
<div class="highlight">
<pre class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">kubectl patch pxc  
</span></span><span class="line"><span class="cl"> --type=merge 
</span></span><span class="line"><span class="cl"> --subresource=status 
</span></span><span class="line"><span class="cl"> --patch '
</span></span><span class="line"><span class="cl">status:
</span></span><span class="line"><span class="cl"> pxc:
</span></span><span class="line"><span class="cl"> version: "8.0.42-33.1"'</span></span></code></pre>
</div>
</div>
</div>
<p><strong>Fixed/Planned Version/s:</strong> 1.20.0</p>
<hr>
<p><a href="https://perconadev.atlassian.net/browse/K8SPXC-1843" target="_blank" rel="noopener noreferrer">K8SPXC-1843</a>: Backups can get stuck in a Running state if the Joiner/Garbd disconnects from the Donor (e.g., due to sst-idle-timeout). Even after the SST process fails and the donor leaves the cluster, the backup process (e.g., xbcloud put) continues indefinitely without timing out, preventing backup completion.</p>
<p><strong>Reported Affected Version/s</strong>: 1.19.0<br>
<strong>Upstream Bug</strong>: Not applicable<br>
<strong>Workaround/Fix</strong>: No workaround available<br>
<strong>Fixed/Planned Version/s</strong>: 1.20.0</p>
<hr>
<p><a href="https://perconadev.atlassian.net/browse/K8SPXC-1831" target="_blank" rel="noopener noreferrer">K8SPXC-1831</a>: When using mysqlAllocator=jemalloc on ARM images, the operator attempts to preload /usr/lib64/libjemalloc.so.1, but only libjemalloc.so.2 is available. This results in preload errors and prevents proper use of the jemalloc allocator.</p>
<p><strong>Reported Affected Version/s</strong>: 1.19.0<br>
<strong>Upstream Bug</strong>: Not applicable<br>
<strong>Workaround/Fix</strong>: Not specified<br>
<strong>Fixed/Planned Version/s</strong>: 1.20.0</p>
<hr>
<p><a href="https://perconadev.atlassian.net/browse/K8SPXC-1830" target="_blank" rel="noopener noreferrer">K8SPXC-1830</a>: ProxySQL monitoring fails in PMM when using caching_sha2_password, causing proxysql_exporter to fail authentication with errors like:</p>
<div class="code-block">
<div class="code-block__header"><button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-1">
<div class="highlight">
<pre class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Error opening connection to ProxySQL:
</span></span><span class="line"><span class="cl">unexpected resp from server for caching_sha2_password, perform full authentication</span></span></code></pre>
</div>
</div>
</div>
<p>This occurs because ProxySQL does not support the required RSA-based full authentication, breaking PMM monitoring integration.<br>
<strong>Reported Affected Version/s</strong>: 1.19.0<br>
<strong>Upstream Bug</strong>: Not applicable<br>
<strong>Workaround/Fix</strong>: Use mysql_native_password<br>
<strong>Fixed/Planned Version/s</strong>: 1.20.0</p>
<hr>
<p><a href="https://perconadev.atlassian.net/browse/K8SPSMDB-1617" target="_blank" rel="noopener noreferrer">K8SPSMDB-1617</a>: Scheduled backups can be triggered even when the MongoDB cluster is not ready (e.g., in initializing state) and without the required safety flags. This leads to failed backup attempts and inconsistent backup behaviour.</p>
<p><strong>Reported Affected Version/s</strong>: 1.22.0<br>
<strong>Upstream Bug</strong>: Not applicable<br>
<strong>Workaround/Fix</strong>: Not specified<br>
<strong>Fixed/Planned Version/s</strong>: Not specified</p>
<hr>
<p><a href="https://perconadev.atlassian.net/browse/K8SPSMDB-1524" target="_blank" rel="noopener noreferrer">K8SPSMDB-1524</a>: The PBM agent continuously triggers resync storage operations, causing backup processes to stall or remain in pending/unknown states. Logs show repeated resync commands being executed without completion, leading to unstable backup behaviour.</p>
<p><strong>Reported Affected Version/s</strong>: 1.21.1<br>
<strong>Upstream Bug</strong>: Not applicable<br>
<strong>Workaround/Fix</strong>: Not specified<br>
<strong>Fixed/Planned Version/s</strong>: 1.22.0</p>
<hr>
<p><a href="https://perconadev.atlassian.net/browse/K8SPG-939" target="_blank" rel="noopener noreferrer">K8SPG-939</a>: Patroni does not propagate labels defined in the PostgreSQL Operator CR, causing failures in environments with strict label policies. As a result, Kubernetes rejects resource creation (e.g., Services) due to missing mandatory labels, preventing cluster reconciliation.</p>
<p><strong>Reported Affected Version/s</strong>: 2.8.2<br>
<strong>Upstream Bug</strong>: Not applicable<br>
<strong>Workaround/Fix</strong>: Not specified<br>
<strong>Fixed/Planned Version/s</strong>: 2.9.0</p>
<hr>
<h2 id="pbm-percona-backup-for-mongodb">PBM [Percona Backup for MongoDB]<a class="anchor-link" id="pbm-percona-backup-for-mongodb"></a></h2>
<p><a href="https://perconadev.atlassian.net/browse/PBM-1683" target="_blank" rel="noopener noreferrer">PBM-1683</a>: The size_uncompressed_h field in pbm describe-backup reports incorrect (inflated) sizes for non-base incremental backups, showing significantly larger values than the actual data size and leading to misleading backup size reporting.</p>
<p><strong>Reported Affected Version/s</strong>: 2.10.0, 2.11.0, 2.12.0<br>
<strong>Upstream Bug</strong>: Not applicable<br>
<strong>Workaround/Fix</strong>: Not specified<br>
<strong>Fixed/Planned Version/s</strong>: 2.14.0</p>
<hr>
<h2 id="psmdb-percona-server-for-mongodb">PSMDB [Percona Server for MongoDB]<a class="anchor-link" id="psmdb-percona-server-for-mongodb"></a></h2>
<p><a href="https://perconadev.atlassian.net/browse/PSMDB-1915" target="_blank" rel="noopener noreferrer">PSMDB-1915</a>: Newer PSMDB packages fail to install or upgrade on RHEL 9.4 due to a dependency on OpenSSL 3.4, which is not available in that OS version. This breaks upgrades (e.g., from 6.0.25 to 6.0.27) and affects multiple major versions.</p>
<p><strong>Reported Affected Version/s</strong>: 6.0.27-21, 7.0.28-15, 8.0.17-6<br>
<strong>Upstream Bug</strong>: Not applicable<br>
<strong>Workaround/Fix</strong>: Not specified<br>
<strong>Fixed/Planned Version/s</strong>: 6.0.27-21, 7.0.28-15, 8.0.17-6</p>
<hr>
<p><a href="https://perconadev.atlassian.net/browse/PSMDB-1998" target="_blank" rel="noopener noreferrer">PSMDB-1998</a>: LDAP authentication can hang indefinitely when the LDAP server is unreachable due to missing timeout handling. This leads to continuously accumulating connections, eventually exhausting file descriptors and causing service disruption or crashes.</p>
<p><strong>Reported Affected Version/s</strong>: 7.0.16-10, 7.0.30-16<br>
<strong>Upstream Bug</strong>: Not applicable<br>
<strong>Workaround/Fix</strong>: No workaround available<br>
<strong>Fixed/Planned Version/s</strong>: 7.0.31-17, 8.0.20-8</p>
<hr>
<h2 id="percona-distribution-for-mysql-orchestrator">Percona Distribution for MySQL [Orchestrator]<a class="anchor-link" id="percona-distribution-for-mysql-orchestrator"></a></h2>
<p><a href="https://perconadev.atlassian.net/browse/DISTMYSQL-584" target="_blank" rel="noopener noreferrer">DISTMYSQL-584</a>: Orchestrator loses SSL-related settings such as SOURCE_SSL_CA and SOURCE_SSL_VERIFY_SERVER_CERT during failover when issuing CHANGE REPLICATION SOURCE, causing replication to run without required security configurations and potentially violating compliance requirements.</p>
<p><strong>Reported Affected Version/s</strong>: 8.4.7<br>
<strong>Upstream Bug</strong>: Not applicable<br>
<strong>Workaround/Fix</strong>: Not specified<br>
<strong>Fixed/Planned Version/s</strong>: Not specified</p>
<hr>
<h2 id="pcsm-percona-clustersync-for-mongodb">PCSM [Percona ClusterSync for MongoDB]<a class="anchor-link" id="pcsm-percona-clustersync-for-mongodb"></a></h2>
<p><a href="https://perconadev.atlassian.net/browse/PCSM-294" target="_blank" rel="noopener noreferrer">PCSM-294</a>: PCSM replication can crash during change replication due to flawed conflict detection and unbatched pipeline generation. This results in oversized aggregation pipelines, memory exhaustion, or invalid $slice operations, causing replication to fail with errors such as stage limit exceeded, buffer limits, or invalid arguments.</p>
<p><strong>Reported Affected Version/s</strong>: 0.7.0<br>
<strong>Upstream Bug</strong>: Not applicable<br>
<strong>Workaround/Fix</strong>: Not specified<br>
<strong>Fixed/Planned Version/s</strong>: 0.8.0</p>
<hr>
<h2 id="pg_tde-percona-transparent-data-encryption-for-postgresql">PG_TDE [Percona Transparent Data Encryption for PostgreSQL]<a class="anchor-link" id="pg_tde-percona-transparent-data-encryption-for-postgresql"></a></h2>
<p><a href="https://perconadev.atlassian.net/browse/PG-2125" target="_blank" rel="noopener noreferrer">PG-2125</a>: pg_tde fails to create/register symmetric keys when using HashiCorp KMIP, returning errors from the KMIP server during key registration. This prevents key setup and blocks encryption workflows for users relying on KMIP integration.</p>
<p><strong>Reported Affected Version/s</strong>: pg_tde 2.1.0<br>
<strong>Upstream Bug</strong>: Not applicable<br>
<strong>Workaround/Fix</strong>: Not specified<br>
<strong>Fixed/Planned Version/s</strong>: pg_tde NEXT</p>
<hr>
<h2 id="summary">Summary<a class="anchor-link" id="summary"></a></h2>
<p>We welcome community input and feedback on all our products. If you find a bug or would like to suggest an improvement or a feature, learn how in our post, <a href="https://www.percona.com/blog/2019/06/12/report-bugs-improvements-new-feature-requests-for-percona-products/" target="_blank" rel="noopener noreferrer">How to Report Bugs, Improvements, New Feature Requests for Percona Products</a>.</p>
<p>For the most up-to-date information, be sure to follow us on <a href="https://twitter.com/percona" target="_blank" rel="noopener noreferrer">Twitter</a>, <a href="https://www.linkedin.com/company/percona" target="_blank" rel="noopener noreferrer">LinkedIn</a>, and <a href="https://www.facebook.com/Percona?fref=ts" target="_blank" rel="noopener noreferrer">Facebook</a>.</p>
<p>Quick References:</p>
<p><a href="https://jira.percona.com" target="_blank" rel="noopener noreferrer">Percona JIRA</a></p>
<p><a href="https://bugs.mysql.com/" target="_blank" rel="noopener noreferrer">MySQL Bug Report</a></p>
<p><a href="https://www.percona.com/blog/2019/06/12/report-bugs-improvements-new-feature-requests-for-percona-products/" target="_blank" rel="noopener noreferrer">Report a Bug in a Percona Product</a></p>

<p>The post <a rel="nofollow" href="https://percona.community/blog/2026/04/03/percona-bug-report-march-2026/">Percona Bug Report: March 2026</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>We ran an internal AI demo competition: Here are the winners!</title>
      <link>https://mariadb.com/resources/blog/we-ran-an-internal-ai-demo-competition-here-are-the-winners/</link>
      <pubDate>Thu, 02 Apr 2026 15:53:37 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.com/">MariaDB</source>
      <description><![CDATA[<p>As developers, we are skeptical of “AI marketing”. We want to see it run. We want to see the actual […]</p>
<p>The post <a rel="nofollow" href="https://mariadb.com/resources/blog/we-ran-an-internal-ai-demo-competition-here-are-the-winners/">We ran an internal AI demo competition: Here are the winners!</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>As developers, we are skeptical of &ldquo;AI marketing&rdquo;. We want to see it run. We want to see the actual techniques and features in action. So, at MariaDB, we decided to organize an AI Demo competition inviting coders (and also non-coders!) to solve actual problems using our cloud and AI capabilities. The results are really cool! We saw applications handling geospatial data&hellip;</p>
<p><a href="https://mariadb.com/resources/blog/we-ran-an-internal-ai-demo-competition-here-are-the-winners/" rel="nofollow">Source</a></p>

<p>The post <a rel="nofollow" href="https://mariadb.com/resources/blog/we-ran-an-internal-ai-demo-competition-here-are-the-winners/">We ran an internal AI demo competition: Here are the winners!</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>MariaDB Vector: How it works. Part III</title>
      <link>https://mariadb.org/mariadb-vector-how-it-works-part-iii/</link>
      <pubDate>Thu, 02 Apr 2026 06:46:48 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.org/">MariaDB.org</source>
      <description><![CDATA[<p>In the previous parts of this series we’ve seen how MariaDB stores vector indexes in a table and how to implement HNSW for a good performance. …<br />
Continue reading \"MariaDB Vector: How it works. Part III\"<br />
The post MariaDB Vector: How it works. Part III appeared first on MariaDB.org.</p>
<p>The post <a rel="nofollow" href="https://mariadb.org/mariadb-vector-how-it-works-part-iii/">MariaDB Vector: How it works. Part III</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>In the <a href="https://mariadb.org/mariadb-vector-how-it-works/" target="_blank" rel="noreferrer noopener">previous</a> <a href="https://mariadb.org/mariadb-vector-how-it-works-part-ii/" target="_blank" rel="noreferrer noopener">parts</a> of this series we&rsquo;ve seen how MariaDB stores vector indexes in a table and how to implement HNSW for a good performance. &hellip; </p>
<p class="link-more"><a href="https://mariadb.org/mariadb-vector-how-it-works-part-iii/" class="more-link">Continue reading<span class="screen-reader-text"> &ldquo;MariaDB Vector: How it works. Part III&rdquo;</span></a></p>
<p>The post <a rel="nofollow" href="https://mariadb.org/mariadb-vector-how-it-works-part-iii/">MariaDB Vector: How it works. Part III</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>

<p>The post <a rel="nofollow" href="https://mariadb.org/mariadb-vector-how-it-works-part-iii/">MariaDB Vector: How it works. Part III</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>InnoDB Buffer Pool Tuning: From Rule-of-Thumb to Real Signals</title>
      <link>https://percona.community/blog/2026/04/02/innodb-buffer-pool-tuning-from-rule-of-thumb-to-real-signals/</link>
      <pubDate>Thu, 02 Apr 2026 00:00:00 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://percona.community/blog/">Percona Community Blog - learn about MySQL, MariaDB, PostgreSQL, and MongoDB</source>
      <description><![CDATA[<p>Introduction Many MySQL setups begin life with a familiar incantation:</p>
<p>The post <a rel="nofollow" href="https://percona.community/blog/2026/04/02/innodb-buffer-pool-tuning-from-rule-of-thumb-to-real-signals/">InnoDB Buffer Pool Tuning: From Rule-of-Thumb to Real Signals</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<h2 id="introduction">Introduction<a class="anchor-link" id="introduction"></a></h2>
<p>Many MySQL setups begin life with a familiar incantation:</p>
<div class="code-block">
<div class="code-block__header"><button class="code-block__copy" type="button" data-copy-target="codeblock-0" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-0">
<div class="highlight">
<pre class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">innodb_buffer_pool_size = 70% of RAM</span></span></code></pre>
</div>
</div>
</div>
<p>&hellip;and then nothing changes.</p>
<p>That&rsquo;s not tuning. That&rsquo;s a starting guess.</p>
<p>Real tuning starts when the workload pushes back.</p>
<hr>
<h2 id="visual-overview">Visual Overview<a class="anchor-link" id="visual-overview"></a></h2>
<p><figure><img decoding="async" src="https://percona.community/blog/2026/04/innodb_buffer_pool_diagram.png" alt="InnoDB Buffer Pool Diagram"></figure>
</p>
<hr>
<p>The InnoDB buffer pool is where database performance is quietly decided. It determines whether your workload hums along in memory or drags itself across disk. If you&rsquo;re not actively observing and tuning it, you&rsquo;re leaving performance on the table.</p>
<p>This guide walks through how to monitor, understand, and tune the buffer pool using real signals instead of guesswork.</p>
<hr>
<h2 id="what-the-buffer-pool-really-is">What the Buffer Pool Really Is<a class="anchor-link" id="what-the-buffer-pool-really-is"></a></h2>
<p>The buffer pool isn&rsquo;t just &ldquo;memory for MySQL.&rdquo; It&rsquo;s a living system under constant pressure:</p>
<ul>
<li>A cache of data and indexes</li>
<li>A write staging area (dirty pages)</li>
<li>A contention zone between reads, writes, and eviction</li>
</ul>
<p>Think of it as your database&rsquo;s working memory. If your working set fits, queries glide. If it doesn&rsquo;t, pages are constantly evicted and reloaded, introducing latency that rarely announces itself clearly.</p>
<hr>
<h2 id="a-simple-mental-model">A Simple Mental Model<a class="anchor-link" id="a-simple-mental-model"></a></h2>
<div class="code-block">
<div class="code-block__header"><button class="code-block__copy" type="button" data-copy-target="codeblock-1" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-1">
<div class="highlight">
<pre class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl"> +---------------------------+
</span></span><span class="line"><span class="cl"> | Buffer Pool |
</span></span><span class="line"><span class="cl"> |---------------------------|
</span></span><span class="line"><span class="cl">Reads ---&gt; | Cached Pages |
</span></span><span class="line"><span class="cl"> | |
</span></span><span class="line"><span class="cl">Writes ---&gt; | Dirty Pages (pending IO) |
</span></span><span class="line"><span class="cl"> | |
</span></span><span class="line"><span class="cl">Eviction -&gt; | LRU / Free List |
</span></span><span class="line"><span class="cl"> +---------------------------+
</span></span><span class="line"><span class="cl"> |
</span></span><span class="line"><span class="cl"> v
</span></span><span class="line"><span class="cl"> Disk (slow)</span></span></code></pre>
</div>
</div>
</div>
<p>Three forces are always competing:</p>
<ul>
<li>Reads want hot data in memory</li>
<li>Writes generate dirty pages</li>
<li>Eviction makes room under pressure</li>
</ul>
<p>Your job is to keep this system balanced.</p>
<hr>
<h2 id="how-to-monitor-the-buffer-pool">How to Monitor the Buffer Pool<a class="anchor-link" id="how-to-monitor-the-buffer-pool"></a></h2>
<h3 id="option-1-quick-snapshot">Option 1: Quick Snapshot<a class="anchor-link" id="option-1-quick-snapshot"></a></h3>
<div class="code-block">
<div class="code-block__header"><span class="code-block__lang">sql</span><button class="code-block__copy" type="button" data-copy-target="codeblock-2" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-2">
<div class="highlight">
<pre class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SHOW</span><span class="w"> </span><span class="n">ENGINE</span><span class="w"> </span><span class="n">INNODB</span><span class="w"> </span><span class="n">STATUS</span><span class="err"></span><span class="k">G</span></span></span></code></pre>
</div>
</div>
</div>
<p>Useful for human inspection. Look for:</p>
<ul>
<li>Buffer pool size</li>
<li>Free buffers</li>
<li>Database pages</li>
<li>Modified (dirty) pages</li>
<li>Page read/write rates</li>
</ul>
<p>Great for debugging. Not ideal for automation.</p>
<hr>
<h3 id="option-2-structured-metrics-recommended">Option 2: Structured Metrics (Recommended)<a class="anchor-link" id="option-2-structured-metrics-recommended"></a></h3>
<div class="code-block">
<div class="code-block__header"><span class="code-block__lang">sql</span><button class="code-block__copy" type="button" data-copy-target="codeblock-3" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-3">
<div class="highlight">
<pre class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">pool_id</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">free_buffers</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">database_pages</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">modified_database_pages</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">FROM</span><span class="w"> </span><span class="n">information_schema</span><span class="p">.</span><span class="n">INNODB_BUFFER_POOL_STATS</span><span class="p">;</span></span></span></code></pre>
</div>
</div>
</div>
<p><strong>Key fields:</strong></p>
<ul>
<li><code>free_buffers</code> &rarr; Available pages (breathing room)</li>
<li><code>database_pages</code> &rarr; Pages holding data</li>
<li><code>modified_database_pages</code> &rarr; Dirty pages waiting to flush</li>
</ul>
<p>Great for automation.</p>
<hr>
<h2 id="the-5-signals-that-actually-matter">The 5 Signals That Actually Matter<a class="anchor-link" id="the-5-signals-that-actually-matter"></a></h2>
<h3 id="1-buffer-pool-hit-ratio-handle-with-care">1. Buffer Pool Hit Ratio (Handle With Care)<a class="anchor-link" id="1-buffer-pool-hit-ratio-handle-with-care"></a></h3>
<p>Yes, it&rsquo;s widely used. No, it&rsquo;s not enough.</p>
<p>A high hit ratio does not mean your system is healthy. It does not capture:</p>
<ul>
<li>Page churn</li>
<li>Eviction pressure</li>
<li>Access patterns</li>
</ul>
<p>You can have a 99% hit ratio and still be IO-bound.</p>
<p>Use it as a sanity check, not a decision-maker.</p>
<hr>
<h3 id="2-free-buffers">2. Free Buffers<a class="anchor-link" id="2-free-buffers"></a></h3>
<div class="code-block">
<div class="code-block__header"><span class="code-block__lang">sql</span><button class="code-block__copy" type="button" data-copy-target="codeblock-4" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-4">
<div class="highlight">
<pre class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="k">SUM</span><span class="p">(</span><span class="n">free_buffers</span><span class="p">)</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">free_buffers</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">FROM</span><span class="w"> </span><span class="n">information_schema</span><span class="p">.</span><span class="n">INNODB_BUFFER_POOL_STATS</span><span class="p">;</span></span></span></code></pre>
</div>
</div>
</div>
<p><strong>Interpretation:</strong></p>
<ul>
<li>Near zero during steady load &rarr; normal</li>
<li>Near zero + rising disk reads &rarr; pressure</li>
<li>Near zero while mostly idle &rarr; suspicious (possible misread or config issue)</li>
</ul>
<hr>
<h3 id="3-dirty-page-percentage">3. Dirty Page Percentage<a class="anchor-link" id="3-dirty-page-percentage"></a></h3>
<div class="code-block">
<div class="code-block__header"><span class="code-block__lang">sql</span><button class="code-block__copy" type="button" data-copy-target="codeblock-5" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-5">
<div class="highlight">
<pre class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">(</span><span class="k">SUM</span><span class="p">(</span><span class="n">modified_database_pages</span><span class="p">)</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="k">SUM</span><span class="p">(</span><span class="n">database_pages</span><span class="p">))</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">100</span><span class="p">.</span><span class="mi">0</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">dirty_pct</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">FROM</span><span class="w"> </span><span class="n">information_schema</span><span class="p">.</span><span class="n">INNODB_BUFFER_POOL_STATS</span><span class="p">;</span></span></span></code></pre>
</div>
</div>
</div>
<p><strong>Interpretation (context matters):</strong></p>
<ul>
<li>0&ndash;5% &rarr; Very clean</li>
<li>5&ndash;20% &rarr; Typical</li>
<li>20&ndash;30%+ &rarr; Potential flushing lag</li>
</ul>
<hr>
<h3 id="4-disk-read-pressure-critical-signal">4. Disk Read Pressure (Critical Signal)<a class="anchor-link" id="4-disk-read-pressure-critical-signal"></a></h3>
<div class="code-block">
<div class="code-block__header"><span class="code-block__lang">sql</span><button class="code-block__copy" type="button" data-copy-target="codeblock-6" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-6">
<div class="highlight">
<pre class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SHOW</span><span class="w"> </span><span class="k">GLOBAL</span><span class="w"> </span><span class="n">STATUS</span><span class="w"> </span><span class="k">LIKE</span><span class="w"> </span><span class="s1">'Innodb_buffer_pool_reads'</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1">-- Take two samples 60s apart and compare</span></span></span></code></pre>
</div>
</div>
</div>
<p>Track the rate of change (reads/sec), not the absolute value.</p>
<p><strong>Interpretation:</strong></p>
<ul>
<li>Rising reads &rarr; Working set does not fit in memory</li>
<li>Flat reads &rarr; Memory is absorbing the workload</li>
</ul>
<hr>
<h3 id="5-read-ahead--eviction-pressure">5. Read Ahead / Eviction Pressure<a class="anchor-link" id="5-read-ahead-eviction-pressure"></a></h3>
<div class="code-block">
<div class="code-block__header"><span class="code-block__lang">sql</span><button class="code-block__copy" type="button" data-copy-target="codeblock-7" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-7">
<div class="highlight">
<pre class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SHOW</span><span class="w"> </span><span class="k">GLOBAL</span><span class="w"> </span><span class="n">STATUS</span><span class="w"> </span><span class="k">LIKE</span><span class="w"> </span><span class="s1">'Innodb_buffer_pool_read_ahead%'</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">SHOW</span><span class="w"> </span><span class="k">GLOBAL</span><span class="w"> </span><span class="n">STATUS</span><span class="w"> </span><span class="k">LIKE</span><span class="w"> </span><span class="s1">'Innodb_buffer_pool_pages_evicted'</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">SHOW</span><span class="w"> </span><span class="k">GLOBAL</span><span class="w"> </span><span class="n">STATUS</span><span class="w"> </span><span class="k">LIKE</span><span class="w"> </span><span class="s1">'Innodb_buffer_pool_reads'</span><span class="p">;</span></span></span></code></pre>
</div>
</div>
</div>
<p><strong>Interpretation:</strong></p>
<ul>
<li>Efficient read-ahead:
<ul>
<li>read_ahead increases</li>
<li>read_ahead_evicted remains low</li>
</ul>
</li>
<li>Inefficient read-ahead (wasted IO):
<ul>
<li>High read_ahead_evicted / read_ahead</li>
<li>Indicates access patterns defeating prefetching</li>
</ul>
</li>
<li>Buffer pool churn:
<ul>
<li>pages_evicted rising</li>
<li>buffer_pool_reads rising</li>
<li>Indicates pages are evicted and re-read from disk</li>
</ul>
</li>
<li>Healthy vs unhealthy eviction:
<ul>
<li>High evictions + stable reads &rarr; normal turnover</li>
<li>High evictions + rising reads &rarr; memory pressure</li>
</ul>
</li>
</ul>
<p>Focus on rates of change over time, not absolute values.</p>
<hr>
<h2 id="detecting-thrashing">Detecting Thrashing<a class="anchor-link" id="detecting-thrashing"></a></h2>
<p>Thrashing is when the buffer pool constantly evicts and reloads pages.</p>
<h3 id="classic-symptoms">Classic Symptoms<a class="anchor-link" id="classic-symptoms"></a></h3>
<ul>
<li>Low or zero free buffers</li>
<li>Increasing disk reads</li>
<li>Stable (but misleading) hit ratio</li>
<li>Spiky query latency</li>
</ul>
<h3 id="visualizing-thrash">Visualizing Thrash<a class="anchor-link" id="visualizing-thrash"></a></h3>
<div class="code-block">
<div class="code-block__header"><button class="code-block__copy" type="button" data-copy-target="codeblock-8" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-8">
<div class="highlight">
<pre class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Time ---&gt;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Memory: [FULL][FULL][FULL][FULL]
</span></span><span class="line"><span class="cl">Reads: &uarr; &uarr;&uarr; &uarr;&uarr;&uarr; &uarr;&uarr;&uarr;&uarr;
</span></span><span class="line"><span class="cl">Latency: - ^ ^^ ^^^
</span></span><span class="line"><span class="cl">Evictions: &uarr; &uarr;&uarr; &uarr;&uarr;&uarr; &uarr;&uarr;&uarr;&uarr;</span></span></code></pre>
</div>
</div>
</div>
<p>If you see this pattern, your working set does not fit in memory.</p>
<hr>
<h2 id="tuning-the-buffer-pool">Tuning the Buffer Pool<a class="anchor-link" id="tuning-the-buffer-pool"></a></h2>
<h3 id="step-1-size-it-intentionally">Step 1: Size It Intentionally<a class="anchor-link" id="step-1-size-it-intentionally"></a></h3>
<p>Instead of blindly assigning 70% of RAM:</p>
<ul>
<li>Observe working set behavior</li>
<li>Monitor free buffers and reads</li>
<li>Increase gradually</li>
</ul>
<p>Avoid starving the OS or filesystem cache.</p>
<hr>
<h3 id="step-2-tune-flushing-behavior">Step 2: Tune Flushing Behavior<a class="anchor-link" id="step-2-tune-flushing-behavior"></a></h3>
<div class="code-block">
<div class="code-block__header"><button class="code-block__copy" type="button" data-copy-target="codeblock-9" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-9">
<div class="highlight">
<pre class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">innodb_max_dirty_pages_pct = 75
</span></span><span class="line"><span class="cl">innodb_io_capacity = 1000
</span></span><span class="line"><span class="cl">innodb_io_capacity_max = 2000</span></span></code></pre>
</div>
</div>
</div>
<ul>
<li>Sustained IO spikes &rarr; increase innodb_io_capacity</li>
<li>Dirty pages climbing &rarr; flushing lag</li>
<li>Sudden stalls &rarr; checkpoint pressure</li>
</ul>
<p><strong>What they control:</strong></p>
<ul>
<li><code>innodb_io_capacity</code> &rarr; Expected steady-state IO throughput</li>
<li><code>innodb_io_capacity_max</code> &rarr; Burst flushing capacity</li>
<li><code>innodb_max_dirty_pages_pct</code> &rarr; Threshold for aggressive flushing</li>
</ul>
<p>&#9888;&#65039; These values should reflect real hardware capability.</p>
<hr>
<h3 id="step-3-buffer-pool-instancesreduce-contention">Step 3: Buffer Pool Instances:Reduce Contention<a class="anchor-link" id="step-3-buffer-pool-instancesreduce-contention"></a></h3>
<p>A practical, battle-tested guideline:</p>
<p>Use 1 instance per ~1GB of buffer pool, up to a reasonable limit.</p>
<p>Buffer Pool Instances: Reducing Contention</p>
<p>The buffer pool can be split into multiple instances, each managing its own internal structures. This helps reduce contention under high concurrency.</p>
<p>Without this, all threads compete for the same buffer pool internals. With multiple instances, that load is distributed.</p>
<hr>
<h3 id="when-it-matters">When It Matters<a class="anchor-link" id="when-it-matters"></a></h3>
<p>Buffer pool instances only help when contention exists. You&rsquo;ll see benefits if your system has:</p>
<ul>
<li>High concurrency (many active threads)</li>
<li>CPU-bound workloads</li>
<li>Mutex contention in InnoDB</li>
</ul>
<p>If your workload is primarily IO-bound, this setting will have little impact.</p>
<hr>
<h3 id="sizing-guidelines">Sizing Guidelines<a class="anchor-link" id="sizing-guidelines"></a></h3>
<p>General guidance:</p>
<ul>
<li>&lt; 1GB buffer pool &rarr; 1 instance</li>
<li>1GB&ndash;8GB &rarr; 2&ndash;4 instances</li>
<li>8GB&ndash;64GB &rarr; 4&ndash;8 instances</li>
<li>64GB+ &rarr; 8&ndash;16 instances</li>
</ul>
<hr>
<h3 id="keep-instances-large-enough">Keep Instances Large Enough<a class="anchor-link" id="keep-instances-large-enough"></a></h3>
<p>Each instance needs enough memory to function efficiently.</p>
<p>Avoid going below ~1GB per instance.</p>
<p>If instances are too small:</p>
<ul>
<li>LRU efficiency drops</li>
<li>Eviction becomes more aggressive</li>
<li>Cache locality suffers</li>
</ul>
<p>Example</p>
<div class="code-block">
<div class="code-block__header"><span class="code-block__lang">sql</span><button class="code-block__copy" type="button" data-copy-target="codeblock-10" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-10">
<div class="highlight">
<pre class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="n">innodb_buffer_pool_size</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">32</span><span class="k">G</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="n">innodb_buffer_pool_instances</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">8</span></span></span></code></pre>
</div>
</div>
</div>
<p>This gives ~4GB per instance, which is well-balanced.</p>
<hr>
<h3 id="common-mistakes">Common Mistakes<a class="anchor-link" id="common-mistakes"></a></h3>
<ul>
<li>Increasing instances without evidence of contention</li>
<li>Matching instance count to CPU cores</li>
<li>Using many instances with a small buffer pool</li>
<li>Expecting this to fix IO bottlenecks</li>
</ul>
<hr>
<h3 id="step-4-understand-resizing-behavior">Step 4: Understand Resizing Behavior<a class="anchor-link" id="step-4-understand-resizing-behavior"></a></h3>
<p>Buffer pool resizing is online in modern MySQL versions, but:</p>
<ul>
<li>It happens in chunks</li>
<li>Controlled by <code>innodb_buffer_pool_chunk_size</code></li>
</ul>
<hr>
<h2 id="real-world-scenarios">Real-World Scenarios<a class="anchor-link" id="real-world-scenarios"></a></h2>
<h3 id="scenario-1-everything-looks-fine-but-its-slow">Scenario 1: &ldquo;Everything Looks Fine&hellip; But It&rsquo;s Slow&rdquo;<a class="anchor-link" id="scenario-1-everything-looks-fine-but-its-slow"></a></h3>
<ul>
<li>High hit ratio</li>
<li>Low free buffers</li>
<li>Rising disk reads</li>
</ul>
<p><strong>Cause:</strong> Working set barely fits</p>
<p><strong>Fix:</strong> Increase buffer pool size gradually</p>
<p>If increasing the buffer pool size does not reduce disk reads, the problem is not memory.</p>
<hr>
<h3 id="scenario-2-write-heavy-workload">Scenario 2: Write-Heavy Workload<a class="anchor-link" id="scenario-2-write-heavy-workload"></a></h3>
<ul>
<li>Dirty pages increasing</li>
<li>Periodic IO spikes</li>
</ul>
<p><strong>Cause:</strong> Flushing cannot keep up</p>
<p><strong>Fix:</strong></p>
<ul>
<li>Increase <code>innodb_io_capacity</code></li>
<li>Adjust dirty page thresholds</li>
</ul>
<hr>
<h3 id="scenario-3-sudden-latency-spikes">Scenario 3: Sudden Latency Spikes<a class="anchor-link" id="scenario-3-sudden-latency-spikes"></a></h3>
<ul>
<li>Sharp performance drops</li>
<li>Disk activity surges</li>
</ul>
<p><strong>Cause:</strong> Checkpoint pressure</p>
<p><strong>Fix:</strong></p>
<ul>
<li>Improve IO capacity tuning</li>
<li>Reduce dirty page buildup</li>
</ul>
<hr>
<h2 id="practical-monitoring-queries">Practical Monitoring Queries<a class="anchor-link" id="practical-monitoring-queries"></a></h2>
<h3 id="buffer-pool-usage-mb">Buffer Pool Usage (MB)<a class="anchor-link" id="buffer-pool-usage-mb"></a></h3>
<div class="code-block">
<div class="code-block__header"><span class="code-block__lang">sql</span><button class="code-block__copy" type="button" data-copy-target="codeblock-11" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-11">
<div class="highlight">
<pre class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">(</span><span class="k">SUM</span><span class="p">(</span><span class="n">database_pages</span><span class="p">)</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">16</span><span class="p">)</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="mi">1024</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">mb_used</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">FROM</span><span class="w"> </span><span class="n">information_schema</span><span class="p">.</span><span class="n">INNODB_BUFFER_POOL_STATS</span><span class="p">;</span></span></span></code></pre>
</div>
</div>
</div>
<p>Assumes default 16KB page size (innodb_page_size).</p>
<h3 id="dirty-page-percentage">Dirty Page Percentage<a class="anchor-link" id="dirty-page-percentage"></a></h3>
<div class="code-block">
<div class="code-block__header"><span class="code-block__lang">sql</span><button class="code-block__copy" type="button" data-copy-target="codeblock-12" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-12">
<div class="highlight">
<pre class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">(</span><span class="n">modified_database_pages</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="n">database_pages</span><span class="p">)</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">100</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">dirty_pct</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">FROM</span><span class="w"> </span><span class="n">information_schema</span><span class="p">.</span><span class="n">INNODB_BUFFER_POOL_STATS</span><span class="p">;</span></span></span></code></pre>
</div>
</div>
</div>
<h3 id="free-buffer-check">Free Buffer Check<a class="anchor-link" id="free-buffer-check"></a></h3>
<div class="code-block">
<div class="code-block__header"><span class="code-block__lang">sql</span><button class="code-block__copy" type="button" data-copy-target="codeblock-13" aria-label="Copy code to clipboard"><br>
<span class="code-block__copy-default">Copy</span><br>
<span class="code-block__copy-success" aria-hidden="true">Copied!</span><br>
</button>
</div>
<div class="code-block__content" id="codeblock-13">
<div class="highlight">
<pre class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="k">SUM</span><span class="p">(</span><span class="n">free_buffers</span><span class="p">)</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">free_buffers</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">FROM</span><span class="w"> </span><span class="n">information_schema</span><span class="p">.</span><span class="n">INNODB_BUFFER_POOL_STATS</span><span class="p">;</span></span></span></code></pre>
</div>
</div>
</div>
<hr>
<h2 id="common-mistakes-1">Common Mistakes<a class="anchor-link" id="common-mistakes"></a></h2>
<ul>
<li>Treating 70% as a rule instead of a starting point</li>
<li>Blindly trusting hit ratio</li>
<li>Ignoring disk read trends</li>
<li>Oversizing and starving the OS</li>
<li>Not tuning IO capacity</li>
<li>Leaving defaults in write-heavy systems</li>
</ul>
<hr>
<h2 id="quick-checklist">Quick Checklist<a class="anchor-link" id="quick-checklist"></a></h2>
<p>If you remember nothing else:</p>
<ul>
<li>Reads increasing? &rarr; working set too big</li>
<li>Free buffers always ~0? &rarr; pressure</li>
<li>Dirty pages high? &rarr; flushing lag</li>
<li>Latency spiking? &rarr; checkpoint or IO saturation</li>
</ul>
<hr>
<h2 id="final-thoughts">Final Thoughts<a class="anchor-link" id="final-thoughts"></a></h2>
<p>The InnoDB buffer pool doesn&rsquo;t fail loudly. It degrades quietly until your disk becomes the bottleneck.</p>
<p>By the time you notice, you&rsquo;re debugging latency instead of preventing it.</p>
<p>Monitor the right signals, and you&rsquo;ll see problems forming before users do.</p>
<p>That&rsquo;s the difference between reacting to performance&hellip; and controlling it.</p>

<p>The post <a rel="nofollow" href="https://percona.community/blog/2026/04/02/innodb-buffer-pool-tuning-from-rule-of-thumb-to-real-signals/">InnoDB Buffer Pool Tuning: From Rule-of-Thumb to Real Signals</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>MariaDB Java Connector 3.5.8 now available</title>
      <link>https://mariadb.com/resources/blog/mariadb-java-connector-3-5-8-now-available/</link>
      <pubDate>Wed, 01 Apr 2026 22:35:19 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.com/">MariaDB</source>
      <description><![CDATA[<p>MariaDB is pleased to announce the immediate availability of the MariaDB Connector/J 3.5.8 release. Release Notes and Changelogs MariaDB Connector/J […]</p>
<p>The post <a rel="nofollow" href="https://mariadb.com/resources/blog/mariadb-java-connector-3-5-8-now-available/">MariaDB Java Connector 3.5.8 now available</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>MariaDB is pleased to announce the immediate availability of the MariaDB Connector/J 3.5.8 release. Download Now Notable items in this release include: See the release notes and changelog for more details and visit mariadb.com/downloads/connectors/connectors-data-access/java8-connector/ to download.</p>
<p><a href="https://mariadb.com/resources/blog/mariadb-java-connector-3-5-8-now-available/" rel="nofollow">Source</a></p>

<p>The post <a rel="nofollow" href="https://mariadb.com/resources/blog/mariadb-java-connector-3-5-8-now-available/">MariaDB Java Connector 3.5.8 now available</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Percona Operator for PostgreSQL 2.9.0: PostgreSQL 18 Default, PVC Snapshot Backups, LDAP Support, and More!</title>
      <link>https://www.percona.com/blog/percona-operator-for-postgresql-2-9-0-postgresql-18-default-pvc-snapshot-backups-ldap-support-and-more/</link>
      <pubDate>Wed, 01 Apr 2026 21:50:13 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://goat.percona.com/blog/">Blog - Percona</source>
      <description><![CDATA[<p>We are excited to announce Percona Operator for PostgreSQL 2.9.0! In this release, we bring significant improvements across database lifecycle management, security, backup/restore, and operational observability, making it easier than ever to run production PostgreSQL on Kubernetes. Here’s a deep dive into what’s new.   Percona Operator for PostgreSQL 2.9.0 PostgreSQL 18 Is Now the … Continued<br />
The post Percona Operator for PostgreSQL 2.9.0: PostgreSQL 18 Default, PVC Snapshot Backups, LDAP Support, and More! appeared first on Percona.</p>
<p>The post <a rel="nofollow" href="https://www.percona.com/blog/percona-operator-for-postgresql-2-9-0-postgresql-18-default-pvc-snapshot-backups-ldap-support-and-more/">Percona Operator for PostgreSQL 2.9.0: PostgreSQL 18 Default, PVC Snapshot Backups, LDAP Support, and More!</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p><span style="font-weight: 400">We are excited to announce <a href="https://docs.percona.com/percona-operator-for-postgresql/2.9.0/ReleaseNotes/Kubernetes-Operator-for-PostgreSQL-RN2.9.0.html"><b>Percona Operator for PostgreSQL 2.9.0</b></a>! </span><span style="font-weight: 400">In this release, we bring significant improvements across database <strong>lifecycle</strong> management, <strong>security</strong>, <strong>backup/restore</strong>, and operational <strong>observability</strong>, making it easier than ever to run <strong>production PostgreSQL on Kubernetes</strong>.</span></p>
<p><span style="font-weight: 400">Here&rsquo;s a deep dive into what&rsquo;s new.</span></p>
<p>&nbsp;</p>
<h2><strong>Percona Operator for PostgreSQL 2.9.0</strong><a class="anchor-link" id="percona-operator-for-postgresql-2-9-0"></a></h2>
<h2><span style="font-weight: 400">PostgreSQL 18 Is Now the Default</span><a class="anchor-link" id="postgresql-18-is-now-the-default"></a></h2>
<p><img decoding="async" loading="lazy" class="alignnone size-full wp-image-43346" src="https://www.percona.com/wp-content/uploads/2026/04/Blog_PG18-1-1024x572-1.png" alt="" width="1024" height="572"></p>
<p><span style="font-weight: 400">Starting with this release, </span><b>PostgreSQL 18</b><span style="font-weight: 400"> is the default version for new cluster deployments. In addition, PostgreSQL 18 delivers improved query planning, better parallelism, enhanced logical replication, and many security hardening improvements.</span></p>
<p><span style="font-weight: 400">If you&rsquo;re still running </span><b>PostgreSQL 13</b><span style="font-weight: 400">, please note that it has reached <a href="https://www.percona.com/blog/postgresql-13-is-reaching-end-of-life-the-time-to-upgrade-is-now/">end-of-life</a> and is no longer supported. We strongly recommend upgrading to a supported version (14 through 18) as soon as possible. </span></p>
<p data-start="58" data-end="196">The following PostgreSQL versions are supported in Percona Operator for PostgreSQL 2.9.0: 14.22-1, 15.17-1, 16.13-1, 17.9-1, and 18.3-1. Other versions may also work, but they have not been officially tested or validated.</p>
<p>&nbsp;</p>
<h2><strong>Major Version Upgrades Are Now Generally Available (GA)</strong><a class="anchor-link" id="major-version-upgrades-are-now-generally-available-ga"></a></h2>
<p><img decoding="async" loading="lazy" class="alignnone size-full wp-image-43345" src="https://www.percona.com/wp-content/uploads/2026/04/Blog_PG_Maj_U-1024x572-1.png" alt="" width="1024" height="572"></p>
<p><span style="font-weight: 400">The </span><b>major upgrade workflow </b><span style="font-weight: 400">for PostgreSQL clusters has graduated to </span><b>General Availability (GA)</b><span style="font-weight: 400">. After extensive testing across upgrade paths and Kubernetes environments, this feature is now production-ready. Specifically, m</span><span style="font-weight: 400">ajor upgrades allow you to move your cluster to a newer PostgreSQL major version, for example, from PostgreSQL 16 to 17 or 18, with minimal disruption (in-place upgrade), all managed by the Operator. As a result, this removes the need for manual </span><b>pg_upgrade</b><span style="font-weight: 400"> procedures and complex migration scripts, letting you keep your clusters up to date with confidence.</span></p>
<p>&nbsp;</p>
<h2><strong>PVC Snapshot Backups: Faster Backups and Restores (Tech Preview)</strong><a class="anchor-link" id="pvc-snapshot-backups-faster-backups-and-restores-tech-preview"></a></h2>
<p><img decoding="async" loading="lazy" class="alignnone size-full wp-image-43344" src="https://www.percona.com/wp-content/uploads/2026/04/Blog_PVC_Snapshot-1024x572-1.png" alt="" width="1024" height="572"></p>
<p><span style="font-weight: 400">One of the most exciting additions in 2.9.0 is </span><b>PVC (Persistent Volume Claim) snapshot support</b><span style="font-weight: 400"> for backups and restores. Rather than streaming data through pgBackRest, PVC snapshots leverage your storage layer&rsquo;s native snapshot capability, dramatically reducing backup time, especially for large databases.</span></p>
<p><span style="font-weight: 400">Key benefits of PVC snapshot backups:</span></p>
<ul>
<li style="font-weight: 400"><b>Significantly faster</b><span style="font-weight: 400"> backup and restore operations for large volumes</span></li>
<li style="font-weight: 400"><b>Point-in-time recovery</b><span style="font-weight: 400"> is supported when combined with pgBackRest WAL archiving</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Currently supports </span><b>cold (offline) backups</b><span style="font-weight: 400"> only.&nbsp;</span><span style="font-weight: 400">We will add a </span><b>hot</b><span style="font-weight: 400"> snapshot (online) in a future release.</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Requires enabling the <code></code></span><i><span style="font-weight: 400">BackupSnapshots</span></i><span style="font-weight: 400"> feature gate</span></li>
</ul>
<p>Combined with pgBackRest&rsquo;s full, differential, and incremental backup types, PVC snapshots give you the flexibility to build a layered backup strategy, routine incrementals for day-to-day protection, and near-instant snapshots before high-risk operations like major upgrades or schema changes, all managed by the same Operator.</p>
<p><span style="font-weight: 400">This feature is in </span><b>Tech Preview</b><span style="font-weight: 400"> in 2.9.0. We encourage users to test it in non-production environments and share feedback via the </span><a href="https://forums.percona.com/c/postgresql/percona-kubernetes-operator-for-postgresql/68"><span style="font-weight: 400">Community Forum</span></a><span style="font-weight: 400"> or </span><a href="https://github.com/percona/percona-postgresql-operator/issues"><span style="font-weight: 400">GitHub issues</span></a><span style="font-weight: 400">.</span></p>
<p>&nbsp;</p>
<h2><strong>WAL Lag Detection for Standby Clusters</strong><a class="anchor-link" id="wal-lag-detection-for-standby-clusters"></a></h2>
<p><img decoding="async" loading="lazy" class="alignnone size-full wp-image-43343" src="https://www.percona.com/wp-content/uploads/2026/04/Blog_Repl_Lag-1024x572-1.png" alt="" width="1024" height="572"></p>
<p><span style="font-weight: 400">Managing standby clusters just got smarter. The Percona Operator for PostgreSQL now supports </span><b>WAL lag detection</b><span style="font-weight: 400">: when a standby cluster falls behind the primary by more than a configurable threshold, the Operator automatically marks its pods as </span><b>unready,</b><span style="font-weight: 400"> and the cluster enters an &ldquo;Initializing&rdquo; state with a <code>StandbyLagging</code> condition.</span></p>
<p><span style="font-weight: 400">As a result, stale standbys from serving traffic silently, improving the reliability of high-availability setups and giving operators clear visibility into replication health. Your team no longer has to guess why something looks wrong. The Operator automatically detects lagging replicas.<br>
</span></p>
<p>&nbsp;</p>
<h2><strong>LDAP Authentication Support</strong><a class="anchor-link" id="ldap-authentication-support"></a></h2>
<p><img decoding="async" loading="lazy" class="alignnone size-full wp-image-43342" src="https://www.percona.com/wp-content/uploads/2026/04/Blog_LDAP-1024x572-1.png" alt="" width="1024" height="572"></p>
<p><span style="font-weight: 400">Security teams can now enforce </span><b>centralized user authentication</b><span style="font-weight: 400"> for PostgreSQL through their corporate LDAP directory. The Operator&rsquo;s new LDAP support allows you to configure PostgreSQL to authenticate users against an LDAP server directly, without requiring manual <code>pg_hba.conf</code> management.</span></p>
<p><span style="font-weight: 400">Two authentication methods are supported:</span></p>
<ul>
<li style="font-weight: 400"><b>Simple bind</b><span style="font-weight: 400"> &ndash; the user&rsquo;s distinguished name (DN) is constructed from a template and used directly to bind</span></li>
<li style="font-weight: 400"><b>Bind-and-search</b><span style="font-weight: 400"> &ndash; the Operator first binds with a service account, searches for the user&rsquo;s DN, then re-binds with the user&rsquo;s credentials</span></li>
</ul>
<p>LDAP integration enables teams to enforce the same identity governance policies for their Kubernetes-hosted PostgreSQL clusters as they do for the rest of their infrastructure. This means no more manually editing pg_hba.conf, no per-cluster credential management, and no separate offboardin, when a user is removed from LDAP, their access to PostgreSQL is gone instantly, across every cluster.</p>
<p>&nbsp;</p>
<h2><strong>Automated TLS Certificate Management via cert-manager</strong><a class="anchor-link" id="automated-tls-certificate-management-via-cert-manager"></a></h2>
<p><img decoding="async" loading="lazy" class="alignnone size-full wp-image-43341" src="https://www.percona.com/wp-content/uploads/2026/04/Blog_Cert_M-1024x572-1.png" alt="" width="1024" height="572"></p>
<p><span style="font-weight: 400">Managing TLS certificates for PostgreSQL clusters is now fully automated with </span><b>cert-manager integration</b><span style="font-weight: 400">. With this integration, the Operator can automatically request, renew, and rotate TLS certificates for cluster communication, eliminating the need to manually manage certificate expiry or rotation scripts.</span></p>
<p><b>Highlights:</b></p>
<ul>
<li>cert-manager automatically renews certificates <strong>30 days before <b>expiration</b></strong></li>
<li><b>Configurable validity periods</b><span style="font-weight: 400"> let teams align certificate lifecycle with their security policies</span></li>
</ul>
<p><span style="font-weight: 400">Overall, this makes it straightforward to enforce encrypted-in-transit policies across all PostgreSQL clusters without operational overhead.</span></p>
<p>&nbsp;</p>
<h2><strong>Official PostGIS Docker Image</strong><a class="anchor-link" id="official-postgis-docker-image"></a></h2>
<p><img decoding="async" loading="lazy" class="alignnone size-full wp-image-43340" src="https://www.percona.com/wp-content/uploads/2026/04/Blog_Gi-1024x572-1.png" alt="" width="1024" height="572"></p>
<p><span style="font-weight: 400">Geospatial workloads on Kubernetes just became easier to manage. Furthermore, this release introduces an </span><b>official PostGIS Docker image</b><span style="font-weight: 400"> maintained by Percona, providing a supported and regularly patched path for running </span><b>PostGIS 3.5.5</b><span style="font-weight: 400"> alongside PostgreSQL. </span><span style="font-weight: 400">With this addition, geospatial PostgreSQL deployments are now a first-class citizen in the Percona Operator ecosystem.</span></p>
<p>&nbsp;</p>
<h2><strong>Operational Improvements:</strong><a class="anchor-link" id="operational-improvements"></a></h2>
<h3><span style="font-weight: 400">pprof Profiling for Troubleshooting</span><a class="anchor-link" id="pprof-profiling-for-troubleshooting"></a></h3>
<p><span style="font-weight: 400">When diagnosing performance issues in the Operator itself, you can now enable </span><b>pprof profiling</b><span style="font-weight: 400"> by setting the </span><i><span style="font-weight: 400">PPROF_BIND_ADDRESS</span></i><span style="font-weight: 400"> environment variable on the Operator pod. Doing so exposes Go&rsquo;s built-in profiling endpoints, enabling CPU and memory analysis without an Operator restart.</span></p>
<h3><span style="font-weight: 400">Custom DNS Suffix Configuration</span><a class="anchor-link" id="custom-dns-suffix-configuration"></a></h3>
<p><span style="font-weight: 400">Running PostgreSQL clusters inside </span><b>vcluster</b><span style="font-weight: 400"> or environments with custom DNS configurations? The new <code>clusterServiceDNSSuffix</code> option lets you specify the DNS suffix used for service discovery, ensuring correct name resolution in non-standard Kubernetes networking setups.</span></p>
<h3><span style="font-weight: 400">Volume Mounting for Sidecar Containers</span><a class="anchor-link" id="volume-mounting-for-sidecar-containers"></a></h3>
<p><span style="font-weight: 400">Sidecar containers can now mount </span><b>PersistentVolumeClaims, Secrets, and ConfigMaps </b><span style="font-weight: 400">directly. The result is a wider range of sidecar use cases, from log exporters needing persistent storage to monitoring agents requiring configuration secrets.<br>
</span></p>
<h3><span style="font-weight: 400">Configurable Operator Leader Election</span><a class="anchor-link" id="configurable-operator-leader-election"></a></h3>
<p><span style="font-weight: 400">If you&rsquo;ve ever seen the Operator crash-loop during a Kubernetes API server blip, for example, when your cluster autoscales and the API server briefly throttles requests, this one is for you.</span></p>
<p><span style="font-weight: 400">In previous versions, the Operator&rsquo;s leader election lease settings were hardcoded. When the API server became slow or temporarily unreachable, the lease wasn&rsquo;t renewed in time, the Operator lost leadership, and immediately restarted, often in a loop. There was no way to tune the timeouts to match your infrastructure.</span></p>
<p><span style="font-weight: 400">v2.9.0 fixes this with four new environment variables:</span></p>
<ul>
<li style="font-weight: 400"><span style="font-weight: 400">Use the PGO_CONTROLLER_LEASE_DURATION, PGO_CONTROLLER_RENEW_DEADLINE, PGO_CONTROLLER_RETRY_PERIOD &ndash; environment variables to adjust timing for lease acquisition and renewal.</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Use the PGO_CONTROLLER_LEADER_ELECTION_ENABLED &ndash; environment variable to turn on or off leader election for single-replica deployments</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Use the PGO_CONTROLLER_LEASE_NAME &ndash; environment variable to use a custom Lease resource for a leader lock.</span></li>
</ul>
<h3><span style="font-weight: 400">Configurable <code>wal_level</code></span><a class="anchor-link" id="configurable-wal_level"></a></h3>
<p><span style="font-weight: 400">You can now configure the <code>wal_level</code> PostgreSQL parameter via the Operator. Particularly useful for clusters without logical replication, setting <code>wal_level = replica</code> reduces unnecessary WAL overhead and improves write performance.</span></p>
<p>&nbsp;</p>
<h2><strong>Deprecations and Breaking Changes</strong><a class="anchor-link" id="deprecations-and-breaking-changes"></a></h2>
<h3><span style="font-weight: 400">PMM2 Support Deprecated</span><a class="anchor-link" id="pmm2-support-deprecated"></a></h3>
<p>Support for <b>PMM2 </b>is now deprecated as it approaches end-of-life. <span style="font-weight: 400">PMM2 will be removed in a future release (two releases from now). Therefore, we strongly encourage all users to migrate to </span><a href="https://docs.percona.com/percona-monitoring-and-management/3/"><b>PMM3</b></a><span style="font-weight: 400"> to continue receiving monitoring support and new features.</span></p>
<h3><span style="font-weight: 400">PostgreSQL 13 Removed</span><a class="anchor-link" id="postgresql-13-removed"></a></h3>
<p><span style="font-weight: 400">PostgreSQL 13 has reached upstream end-of-life and this release drops it. If you are still running PostgreSQL 13 clusters, please upgrade to a supported version before updating the Operator.</span></p>
<h3><span style="font-weight: 400"><code>pg_stat_monitor</code> Disabled by Default</span><a class="anchor-link" id="pg_stat_monitor-disabled-by-default"></a></h3>
<p><span style="font-weight: 400">The<b style="font-weight: 400">&nbsp;</b><code>pg_stat_monitor</code> is disabled </span><b>by default </b>now <span style="font-weight: 400">to prevent potential memory issues in production clusters. If you rely on this extension, you can re-enable it explicitly via the custom resource.</span></p>
<p>&nbsp;</p>
<h2><strong>Conclusion</strong><a class="anchor-link" id="conclusion"></a></h2>
<p><span style="font-weight: 400">Percona Operator for PostgreSQL v2.9.0 is a enterprise level features release that continues to push the boundaries of what&rsquo;s possible when running PostgreSQL on Kubernetes. From making PostgreSQL 18 the new default to introducing PVC snapshot-based backups that can complete in seconds regardless of database size, this release squarely targets speed, security, and operational confidence.</span><span style="font-weight: 400"><br>
</span><span style="font-weight: 400"><br>
</span><span style="font-weight: 400">We encourage you to </span><a href="https://docs.percona.com/percona-operator-for-postgresql/"><span style="font-weight: 400">try Percona Operator for PostgreSQL v2.9.0</span></a><span style="font-weight: 400">, explore the full </span><a href="https://docs.percona.com/percona-operator-for-postgresql/latest/ReleaseNotes/Kubernetes-Operator-for-PostgreSQL-RN2.9.0.html"><span style="font-weight: 400">release notes</span></a><span style="font-weight: 400">, and share your feedback with the community. As always, you can reach us through the </span><a href="https://forums.percona.com/"><span style="font-weight: 400">Community Forum</span></a><span style="font-weight: 400">&nbsp;or file issues on </span><a href="https://github.com/percona/percona-postgresql-operator"><span style="font-weight: 400">GitHub</span></a><span style="font-weight: 400">.</span></p>
<p>&nbsp;</p>
<p>The post <a href="https://www.percona.com/blog/percona-operator-for-postgresql-2-9-0-postgresql-18-default-pvc-snapshot-backups-ldap-support-and-more/">Percona Operator for PostgreSQL 2.9.0: PostgreSQL 18 Default, PVC Snapshot Backups, LDAP Support, and More!</a> appeared first on <a href="https://www.percona.com">Percona</a>.</p>

<p>The post <a rel="nofollow" href="https://www.percona.com/blog/percona-operator-for-postgresql-2-9-0-postgresql-18-default-pvc-snapshot-backups-ldap-support-and-more/">Percona Operator for PostgreSQL 2.9.0: PostgreSQL 18 Default, PVC Snapshot Backups, LDAP Support, and More!</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Benchmarking MyRocks vs. InnoDB in Memory-Constrained Environments</title>
      <link>https://www.percona.com/blog/benchmarking-myrocks-vs-innodb-in-memory-constrained-environments/</link>
      <pubDate>Wed, 01 Apr 2026 13:31:27 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://www.percona.com/blog/">Percona Database Performance Blog</source>
      <description><![CDATA[<p>Benchmarking MyRocks vs. InnoDB in Memory-Constrained Environments It is a well-known fact in the database world that InnoDB is incredibly fast when the entire database fits into memory. But what happens when your data grows beyond your available RAM? MyRocks, built on RocksDB, is frequently recommended as a superior choice for environments constrained by memory, […]</p>
<p>The post <a rel="nofollow" href="https://www.percona.com/blog/benchmarking-myrocks-vs-innodb-in-memory-constrained-environments/">Benchmarking MyRocks vs. InnoDB in Memory-Constrained Environments</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>Benchmarking MyRocks vs. InnoDB in Memory-Constrained Environments It is a well-known fact in the database world that InnoDB is incredibly fast when the entire database fits into memory. But what happens when your data grows beyond your available RAM? MyRocks, built on RocksDB, is frequently recommended as a superior choice for environments constrained by memory, [&hellip;]</p>

<p>The post <a rel="nofollow" href="https://www.percona.com/blog/benchmarking-myrocks-vs-innodb-in-memory-constrained-environments/">Benchmarking MyRocks vs. InnoDB in Memory-Constrained Environments</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>What’s New in MariaDB AI RAG 1.1: Ingestion, Reranking, and Docker Deployment</title>
      <link>https://mariadb.com/resources/blog/whats-new-in-mariadb-ai-rag-1-1-ingestion-reranking-and-docker-deployment/</link>
      <pubDate>Tue, 31 Mar 2026 17:38:01 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.com/">MariaDB</source>
      <description><![CDATA[<p>Moving a RAG (Retrieval-Augmented Generation) application from a local prototype to a production-grade system requires solving for data messy ingestion, […]</p>
<p>The post <a rel="nofollow" href="https://mariadb.com/resources/blog/whats-new-in-mariadb-ai-rag-1-1-ingestion-reranking-and-docker-deployment/">What’s New in MariaDB AI RAG 1.1: Ingestion, Reranking, and Docker Deployment</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>Moving a RAG (Retrieval-Augmented Generation) application from a local prototype to a production-grade system requires solving for data messy ingestion, retrieval precision, and deployment complexity. MariaDB AI RAG 1.1 addresses these bottlenecks with improvements to the ingestion pipeline, more granular retrieval controls, and a containerized deployment model. MariaDB AI RAG is currently in&hellip;</p>
<p><a href="https://mariadb.com/resources/blog/whats-new-in-mariadb-ai-rag-1-1-ingestion-reranking-and-docker-deployment/" rel="nofollow">Source</a></p>

<p>The post <a rel="nofollow" href="https://mariadb.com/resources/blog/whats-new-in-mariadb-ai-rag-1-1-ingestion-reranking-and-docker-deployment/">What’s New in MariaDB AI RAG 1.1: Ingestion, Reranking, and Docker Deployment</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Know a MariaDB champion? Submit a nomination</title>
      <link>https://mariadb.org/know-a-mariadb-champion-submit-a-nomination/</link>
      <pubDate>Mon, 30 Mar 2026 14:01:00 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.org/">MariaDB.org</source>
      <description><![CDATA[<p>One of the things I really like about open source is that a project is never only about the software.<br />
Yes, code is important. Very important. …<br />
Continue reading \"Know a MariaDB champion? Submit a nomination\"<br />
The post Know a MariaDB champion? Submit a nomination appeared first on MariaDB.org.</p>
<p>The post <a rel="nofollow" href="https://mariadb.org/know-a-mariadb-champion-submit-a-nomination/">Know a MariaDB champion? Submit a nomination</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>One of the things I really like about open source is that a project is never only about the software.<br>
Yes, code is important. Very important. &hellip; </p>
<p class="link-more"><a href="https://mariadb.org/know-a-mariadb-champion-submit-a-nomination/" class="more-link">Continue reading<span class="screen-reader-text"> &ldquo;Know a MariaDB champion? Submit a nomination&rdquo;</span></a></p>
<p>The post <a rel="nofollow" href="https://mariadb.org/know-a-mariadb-champion-submit-a-nomination/">Know a MariaDB champion? Submit a nomination</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>

<p>The post <a rel="nofollow" href="https://mariadb.org/know-a-mariadb-champion-submit-a-nomination/">Know a MariaDB champion? Submit a nomination</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Contributions As a Cost-saver</title>
      <link>https://mariadb.org/contributions-as-a-cost-saver/</link>
      <pubDate>Mon, 30 Mar 2026 12:18:04 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.org/">MariaDB.org</source>
      <description><![CDATA[<p>The economics of open source contribution development. And some questions.<br />
The post Contributions As a Cost-saver appeared first on MariaDB.org.</p>
<p>The post <a rel="nofollow" href="https://mariadb.org/contributions-as-a-cost-saver/">Contributions As a Cost-saver</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>The economics of open source contribution development. And some questions.</p>
<p>The post <a rel="nofollow" href="https://mariadb.org/contributions-as-a-cost-saver/">Contributions As a Cost-saver</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>

<p>The post <a rel="nofollow" href="https://mariadb.org/contributions-as-a-cost-saver/">Contributions As a Cost-saver</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>PostgreSQL: Bye-Bye MD5 Authentication. What’s Next?</title>
      <link>https://www.percona.com/blog/postgresql-bye-bye-md5-authentication-whats-next/</link>
      <pubDate>Fri, 27 Mar 2026 21:33:06 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://goat.percona.com/blog/">Blog - Percona</source>
      <description><![CDATA[<p>Introduction MD5 has been the most popular algorithm for encoding passwords in PostgreSQL and other database systems. It is simple to implement, causes less overhead and less latency for completing the authentication, and this is why it has been the most preferred method. However, a discussion thread in the PG community has given a signal … Continued<br />
The post PostgreSQL: Bye-Bye MD5 Authentication. What’s Next? appeared first on Percona.</p>
<p>The post <a rel="nofollow" href="https://www.percona.com/blog/postgresql-bye-bye-md5-authentication-whats-next/">PostgreSQL: Bye-Bye MD5 Authentication. What’s Next?</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<h3><b>Introduction</b><a class="anchor-link" id="introduction"></a></h3>
<p><span style="font-weight: 400">MD5 has been the most popular algorithm for encoding passwords in PostgreSQL and other database systems. It is simple to implement, causes less overhead and less latency for completing the authentication, and this is why it has been the most preferred method. However, a </span><a href="https://www.postgresql.org/message-id/ZwbfpJJol7lDWajL@nathan"><span style="font-weight: 400">discussion thread</span></a><span style="font-weight: 400"> in the PG community has given a signal to discontinue support for MD5 authentication, which is indeed a big change. In this blog post, I will cover the basics of MD5 authentication, its dark side, implementation in PostgreSQL and </span><span style="font-weight: 400">a potential solution in the form of scram-sha-256</span><span style="font-weight: 400">.</span></p>
<h3><b>Background</b><a class="anchor-link" id="background"></a></h3>
<p><span style="font-weight: 400">It is not unusual to see the following entries in pg_hba.conf, but they will soon become a page of history.</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">host all all 0.0.0.0/0 md5
host all all 127.0.0.1 md5
host all all 192.168.0.0/24 md5</pre>
<p><span style="font-weight: 400">In future versions, PostgreSQL may issue warnings or even discard authentication requests by displaying an error. MD5 usage will gradually phase out as planned. The following is a proposal in a community.(Reference </span><a href="https://www.postgresql.org/message-id/ZwbfpJJol7lDWajL@nathan"><span style="font-weight: 400">link</span></a><span style="font-weight: 400">).</span></p>
<blockquote><p>1. In v18, continue to support MD5 passwords, but place several notes in the documentation and release notes that unambiguously indicate that MD5 password support is deprecated and will be removed in a future release.<br>
2. In v19, allow upgrading with MD5 passwords and allow authenticating with them, but disallow creating new ones (i.e., restrict/remove password_encryption and don&rsquo;t allow setting pre-hashed MD5 passwords).<br>
3.In v20, allow upgrading with MD5 passwords, but disallow using them for authentication.&nbsp; Users would only be able to update these passwords to SCRAM-SHA-256 after upgrading.<br>
4. In v21, disallow upgrading with MD5 passwords.&nbsp; At this point, there should be no remaining MD5 password support in Postgres.</p></blockquote>
<h6><span style="font-weight: 400">Note :- Till time, this is just a proposal and not a confir</span>mation. However, MD5 will be surely unsupported in future versions.</h6>
<p><span style="font-weight: 400">Before understanding MD5 in PostgreSQL, we will review its basics.</span></p>
<h3><b>MD5</b><a class="anchor-link" id="md5"></a></h3>
<p><span style="font-weight: 400">Designed by &ndash; Roland Rivest in 1991</span></p>
<p><span style="font-weight: 400">Precursor &ndash; MD4</span></p>
<p><span style="font-weight: 400">Type &ndash; 128-bit encryption</span></p>
<p><span style="font-weight: 400">The algorithm receives a text or file as input and produces a 128-bit hash(or a 32-character-long hex code) as output. As it can receive text files as an input, it is also used for calculating checksums (md5sum).</span></p>
<p><span style="font-weight: 400">In the MD5 authentication process, the text is divided into 512-bytes of blocks and passed to the hashing function that ultimately produces a 32-digit hexadecimal number. The image below describes the process in detail.</span></p>
<p><img decoding="async" loading="lazy" class="alignnone size-full wp-image-43323" src="https://www.percona.com/wp-content/uploads/2026/04/Screenshot-2026-03-11-at-4.15.36-PM.png" alt="" width="980" height="654"></p>
<p><span style="font-weight: 400">MD5 is not reversible; no program or method can unhash an MD5 hash. In other words, it is not possible to generate the original text or message from the available hash value. Whenever we use MD5 for authentication, it converts the supplied password to an MD5 hash and compares it with the stored MD5 value. Whenever MD5 matches, the authentication succeeds, otherwise it rejects the access.</span></p>
<p><span style="font-weight: 400">Wow. The password-cracking does not work here, so it is immune to attacks.</span></p>
<p><span style="font-weight: 400">Right?&nbsp;</span><span style="font-weight: 400">Unfortunately, no! MD5 is not safe from vulnerability attacks. Let us understand it.</span></p>
<p><span style="text-decoration: underline"><span style="font-weight: 400">Collision attacks in MD5</span></span></p>
<p><span style="font-weight: 400">As we saw earlier, MD5 is a hashing algorithm that generates a hex digest. In every hashing algorithm, there is a concept called </span><a href="https://en.wikipedia.org/wiki/Collision_attack"><span style="font-weight: 400">collision</span></a><span style="font-weight: 400"> which means different inputs generating the same hash value. MD5 is no exception. Discovering another string that matches my password&rsquo;s hash is equivalent to believing my data is lost. The first incident was reported in 1996.</span></p>
<p><span style="font-weight: 400">Sounds horrible! Isn&rsquo;t it? </span><span style="font-weight: 400">Indeed, it is. But, this is expected.</span></p>
<p><span style="font-weight: 400">How?</span></p>
<p><span style="font-weight: 400">This is because any text is converted to a fixed 32-digit hexadecimal number, while there is no limit on the size of the input text.</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">percona@XYZ ~ $ md5 -s "Wishing you clarity, strength, and steady progress today, turning challenges into opportunities and efforts into success."
d686cad09daac517b2859305181067ac

percona@XYZ ~ $ md5 -s "May today bring fresh energy, clear thoughts, and quiet confidence. Take one step at a time, trust your experience, learn from setbacks, and celebrate progress. Consistent effort, patience, and curiosity will guide you forward, helping you create meaningful results and lasting impact in work and life for years to come."
2f61acd9c2bd4397406b5b056c0b7edc</pre>
<p><span style="font-weight: 400">As we can see, different texts of different lengths generate fixed-size hashes; many strings or patterns can generate the same hash, while the text can range from several bytes to GBs. Considering the facts, it is absolutely impossible to identify the number of occurrences that generate the same hash; it could be 1000, 10000 or even billions and more. Virtually, we cannot predict how many strings or texts would generate the same hash.</span></p>
<p><span style="font-weight: 400">To understand it more clearly, refer to the example below of 2 different strings(<em>TEXTCOLLBYfGiJUETHQ4h<span style="text-decoration: underline"><strong>A</strong></span>cKSMd5zYpgqf1YRDhkmxHkhPWptrkoyz28wnI9V0aHeAuaKnak</em> and <em>TEXTCOLLBYfGiJUETHQ4h<span style="text-decoration: underline"><strong>E</strong></span>cKSMd5zYpgqf1YRDhkmxHkhPWptrkoyz28wnI9V0aHeAuaKnak</em>) that generate the same hash. The strings were taken from the </span><a href="https://www.johndcook.com/blog/2024/03/20/md5-hash-collision/"><span style="font-weight: 400">page</span></a><span style="font-weight: 400">.</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">percona@XYZ ~ $ md5 -s TEXTCOLLBYfGiJUETHQ4hAcKSMd5zYpgqf1YRDhkmxHkhPWptrkoyz28wnI9V0aHeAuaKnak
faad49866e9498fc1719f5289e7a0269
percona@XYZ ~ $ md5 -s TEXTCOLLBYfGiJUETHQ4hEcKSMd5zYpgqf1YRDhkmxHkhPWptrkoyz28wnI9V0aHeAuaKnak
faad49866e9498fc1719f5289e7a0269</pre>
<p><span style="font-weight: 400">However, by changing the letter in the same place, the string(<em>TEXTCOLLBYfGiJUETHQ4h<span style="text-decoration: underline"><strong>C</strong></span>cKSMd5zYpgqf1YRDhkmxHkhPWptrkoyz28wnI9V0aHeAuaKnak</em>) generates a different hash.</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">percona@XYZ ~ $ md5 -s TEXTCOLLBYfGiJUETHQ4hCcKSMd5zYpgqf1YRDhkmxHkhPWptrkoyz28wnI9V0aHeAuaKnak
8c88b1b008b35ed2f3f4100e7faea8c7</pre>
<p><span style="font-weight: 400">The prediction of the string is not as simple as it looks for the first time. As of now, it is not possible to crack MD5 using GPU or quantum computing as it takes several years. But, the experts are very confident that quantum computers will become powerful enough to crack MD5 in the next 10 years.</span></p>
<p><span style="font-weight: 400">The majority of attackers these days use dictionary attacks or any trivial methods, and they succeed because the access is just one hash match away.</span></p>
<h3><b>PostgreSQL and MD5</b><a class="anchor-link" id="postgresql-and-md5"></a></h3>
<p><span style="font-weight: 400">By what we saw in the last section, you must be convinced that MD5 is an unreliable encryption method. So, shouldn&rsquo;t it have been removed long back?</span></p>
<p><span style="font-weight: 400">Also, isn&rsquo;t it too late to take a bold decision on its discontinuation?&nbsp; </span><span style="font-weight: 400">Many PostgreSQL systems might have already been affected by various hacks and crashes and been subjected to data stealing.</span></p>
<p><span style="font-weight: 400">Should we stop using PostgreSQL and move to any other database if it&rsquo;s not too late? </span></p>
<p><span style="font-weight: 400">Well, it&rsquo;s time for a litmus test. Let us test the fear.</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">postgres=# create user md5_test with password 'TEXTCOLLBYfGiJUETHQ4hAcKSMd5zYpgqf1YRDhkmxHkhPWptrkoyz28wnI9V0aHeAuaKnak';
CREATE ROLE
postgres=# /q</pre>
<pre class="urvanov-syntax-highlighter-plain-tag">postgres@XYZ:~$ export PGPASSWORD=TEXTCOLLBYfGiJUETHQ4hEcKSMd5zYpgqf1YRDhkmxHkhPWptrkoyz28wnI9V0aHeAuaKnak
postgres@XYZ:~$ psql -U md5_test -h localhost postgres
psql: error: connection to server at "localhost" (127.0.0.1), port 5432 failed: FATAL:&amp;nbsp; password authentication failed for user "md5_test"&lt;br&gt;connection to server at "localhost" (127.0.0.1), port 5432 failed: FATAL:&amp;nbsp; password authentication failed for user "md5_test"</pre>
<p><span style="font-weight: 400">What! All in vain. What we have learnt so far makes no sense.</span></p>
<p><span style="font-weight: 400">Wait, refrain from making quick judgments! It does not generate the same hash that we obtained in the previous section(</span><em><span style="font-weight: 400">faad49866e9498fc1719f5289e7a0269</span></em><span style="font-weight: 400">).</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">postgres=# select rolname, rolpassword from pg_authid where rolname='md5_test';
&nbsp;rolname&nbsp; | &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; rolpassword&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
----------+-------------------------------------
&nbsp;md5_test | md5c5e4bbac9b29d19bf08a6fbb87abe3f0
(1 row)</pre>
<p><span style="font-weight: 400">The PG community was not unaware of this issue, and it was addressed. In PostgreSQL, MD5 authentication string is stored using a combination of username and password. The below formula is the most suitable one for MD5 hash with PG(Reference </span><a href="https://www.postgresql.org/docs/18/protocol-flow.html"><span style="font-weight: 400">link</span></a><span style="font-weight: 400">).</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">'md5' + md5(password, username)</pre>
<p><span style="font-weight: 400">We can validate the formula as below.</span></p>
<pre class="urvanov-syntax-highlighter-plain-tag">percona@XYZ ~ % export USER=md5_test
percona@XYZ ~ % export PASSWORD=TEXTCOLLBYfGiJUETHQ4hAcKSMd5zYpgqf1YRDhkmxHkhPWptrkoyz28wnI9V0aHeAuaKnak
percona@XYZ ~ % echo md5`md5 -s $PASSWORD$USER`
md5c5e4bbac9b29d19bf08a6fbb87abe3f0</pre>
<p><span style="font-weight: 400">So, can we consider MD5 a secured algorithm in PostgreSQL? Unequivocally, yes.</span></p>
<p><span style="font-weight: 400">However, an MD5-hash leak may make the database vulnerable against attacks as it&rsquo;s not very difficult for attackers to generate a hash-matching string. So, the deprecation of MD5 is a wise decision.</span></p>
<h3><b>Solution: scram-sha-256</b><a class="anchor-link" id="solution-scram-sha-256"></a></h3>
<p><span style="font-weight: 400">PostgreSQL supports various methods of authentication.&nbsp;</span></p>
<ul>
<li style="font-weight: 400"><span style="font-weight: 400">GSSAPI</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Radius</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">LDAP</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Cert</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">PAM</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Password(md5, password, scram-sha-256)</span></li>
</ul>
<p><span style="font-weight: 400">Some methods, such as peer(not for a client-server model), trust, ident, are not suggested unless it&rsquo;s absolutely inevitable as they make databases more open to intruders.</span></p>
<p><span style="font-weight: 400">An additional layer of authentication is always preferred as long as it is in a secure network. We should keep in our minds that this could become a single point of exposure.</span></p>
<p><span style="font-weight: 400">Those who don&rsquo;t want an additional tier of authentication may use scram-sha-256. It is stronger over md5.</span></p>
<p><span style="text-decoration: underline"><span style="font-weight: 400">scram-sha-256</span></span></p>
<p><span style="font-weight: 400">In version 10, the community introduced a new method for password authentication: scram-sha-256. The major advantage is its length, which is 256 bits. Also, there are some additional security features that make it more adoptive. The below picture shows the string along with a description of every part.</span></p>
<p><img decoding="async" loading="lazy" class="alignnone size-full wp-image-43322" src="https://www.percona.com/wp-content/uploads/2026/04/Screenshot-2026-03-11-at-4.14.24-PM.png" alt="" width="1148" height="652"></p>
<p><span style="font-weight: 400">All the parts are used for authentication. At the time of authentication, a client reads the server key and generates a client key and passes it back to the server. The server verifies and allows access to the client.</span></p>
<p><span style="font-weight: 400">The image below shows the operations of scram-sha-256.</span></p>
<p><img decoding="async" loading="lazy" class="alignnone size-full wp-image-43321" src="https://www.percona.com/wp-content/uploads/2026/04/Screenshot-2026-03-11-at-4.11.54-PM.png" alt="" width="932" height="578"></p>
<p><span style="font-weight: 400">scram-sha-256 doesn&rsquo;t send plaintext passwords over the network, also the authentication requires participation from the client as well. Due to these features, scram-sha-256 is more reliable and secure.</span></p>
<p><span style="font-weight: 400">In recent PG versions, the default authentication method is scram-sha-256. For the users who use older versions, they should switch to scram-sha-256 or upgrade PostgreSQL to the latest version.</span></p>
<p><span style="text-decoration: underline"><span style="font-weight: 400">Downsides of scram-sha-256</span></span></p>
<p><span style="font-weight: 400">Having said that scram-sha-256 is an answer to pass-the-hash attack, it is still a troublemaker on occasions.&nbsp;</span></p>
<ul>
<li style="font-weight: 400"><span style="font-weight: 400">Authentication requires higher time than MD5 as it takes 6 rounds of communication to finish the process.</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">It performs a series of operations that are CPU-intensive. As a result, CPU usage spikes.</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">While using Pgbouncer in the transaction mode, the latency spike becomes evident.</span></li>
<li style="font-weight: 400"><span style="font-weight: 400">Using a pooler is recommended when a connection churn is very high because establishing connection would increase the CPU utilisation.</span></li>
</ul>
<p><span style="font-weight: 400">Despite having so many odds, it offers enhanced security and multiple-layers of communication, which makes it trustworthy. To study scram-sha-256 in detail, kindly refer to the </span><a href="https://datatracker.ietf.org/doc/html/rfc7677"><span style="font-weight: 400">page</span></a><span style="font-weight: 400">.</span></p>
<p><span style="font-weight: 400">Another question, is it possible to crack scram-sha-256? We certainly cannot rule out the possibility. In theory, every software program is susceptible to hack attacks. But, if we take these words in letters and spirit, we need to go back to pens and notebooks or even stone-carving methods to store our data. In fact, the majority of systems keep running without any security breaches, but this cannot be an argument of its acceptance in spite of the fact that it is well-designed and more reliable. Now, what?</span></p>
<p><span style="font-weight: 400">While the most secured databases in the world are vulnerable to attacks, we need to have the number of incidents and probability of such occurrences. As long as no incidents are reported, my database is safe. This might sound diplomatic or compromising, but it is the most convenient position.</span></p>
<h3><b>Conclusion</b><a class="anchor-link" id="conclusion"></a></h3>
<p><span style="font-weight: 400">MD5 has been very popular, but it has many flaws that makes it less reliable and vulnerable. In PostgreSQL, MD5 authentication was implemented to overcome the issues found in the traditional MD5 algorithm. However, the possibility of getting hacked cannot be ruled out, so it is inevitable to phase it out gradually. scram-sha-256 is a more robust and preferable option and secured over MD5.</span></p>
<p><span style="font-weight: 400">Those who still rely on MD5 authentication, it is highly recommended to move to scram-sha-256 or any other reliable method. To ensure that your database is up to date and secured, kindly connect to </span><a href="https://www.percona.com/postgresql/support-and-services"><span style="font-weight: 400">Percona PostgreSQL experts</span></a><span style="font-weight: 400">.</span></p>
<p>The post <a href="https://www.percona.com/blog/postgresql-bye-bye-md5-authentication-whats-next/">PostgreSQL: Bye-Bye MD5 Authentication. What&rsquo;s Next?</a> appeared first on <a href="https://www.percona.com">Percona</a>.</p>

<p>The post <a rel="nofollow" href="https://www.percona.com/blog/postgresql-bye-bye-md5-authentication-whats-next/">PostgreSQL: Bye-Bye MD5 Authentication. What’s Next?</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>2026 – MySQL Ecosystem Performance Benchmark Report</title>
      <link>https://www.percona.com/blog/2026-mysql-ecosystem-performance-benchmark-report/</link>
      <pubDate>Thu, 26 Mar 2026 10:04:22 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://www.percona.com/blog/">Percona Database Performance Blog</source>
      <description><![CDATA[<p>By Percona Lab Results  ·  2026  ·  MySQL MariaDB Percona Benchmark Database MySQL Ecosystem Performance Benchmark Report 2026 Comparative Analysis of InnoDB-Compatible Engines — Percona Lab Results Repository: github.com/Percona-Lab-results/2026-interactive-metrics Interactive graphs available: Explore the full dataset dynamically — click any graph below to open the interactive version. OLTP Read-Write Local — interactive benchmark graph OLTP […]</p>
<p>The post <a rel="nofollow" href="https://www.percona.com/blog/2026-mysql-ecosystem-performance-benchmark-report/">2026 – MySQL Ecosystem Performance Benchmark Report</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>By Percona Lab Results &nbsp;&middot;&nbsp; 2026 &nbsp;&middot;&nbsp; MySQL MariaDB Percona Benchmark Database MySQL Ecosystem Performance Benchmark Report 2026 Comparative Analysis of InnoDB-Compatible Engines &mdash; Percona Lab Results Repository: github.com/Percona-Lab-results/2026-interactive-metrics Interactive graphs available: Explore the full dataset dynamically &mdash; click any graph below to open the interactive version. OLTP Read-Write Local &mdash; interactive benchmark graph OLTP [&hellip;]</p>

<p>The post <a rel="nofollow" href="https://www.percona.com/blog/2026-mysql-ecosystem-performance-benchmark-report/">2026 – MySQL Ecosystem Performance Benchmark Report</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>MariaDB observability – results from the poll: the community has clearly chosen its default stack</title>
      <link>https://mariadb.org/mariadb-observability-results-from-the-poll-the-community-has-clearly-chosen-its-default-stack/</link>
      <pubDate>Thu, 26 Mar 2026 08:35:54 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.org/">MariaDB.org</source>
      <description><![CDATA[<p>Before I share my takeaway from this MariaDB observability poll, I would like to thank all participants and highlight that these recent polls are very popular, and your participation makes us happy. …<br />
Continue reading \"MariaDB observability – results from the poll: the community has clearly chosen its default stack\"<br />
The post MariaDB observability – results from the poll: the community has clearly chosen its default stack appeared first on MariaDB.org.</p>
<p>The post <a rel="nofollow" href="https://mariadb.org/mariadb-observability-results-from-the-poll-the-community-has-clearly-chosen-its-default-stack/">MariaDB observability – results from the poll: the community has clearly chosen its default stack</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>Before I share my takeaway from this MariaDB observability poll, I would like to thank all participants and highlight that these recent polls are very popular, and your participation makes us happy. &hellip; </p>
<p class="link-more"><a href="https://mariadb.org/mariadb-observability-results-from-the-poll-the-community-has-clearly-chosen-its-default-stack/" class="more-link">Continue reading<span class="screen-reader-text"> &ldquo;MariaDB observability &ndash; results from the poll: the community has clearly chosen its default stack&rdquo;</span></a></p>
<p>The post <a rel="nofollow" href="https://mariadb.org/mariadb-observability-results-from-the-poll-the-community-has-clearly-chosen-its-default-stack/">MariaDB observability &ndash; results from the poll: the community has clearly chosen its default stack</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>

<p>The post <a rel="nofollow" href="https://mariadb.org/mariadb-observability-results-from-the-poll-the-community-has-clearly-chosen-its-default-stack/">MariaDB observability – results from the poll: the community has clearly chosen its default stack</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>MariaDB Vector: How it works. Part II</title>
      <link>https://mariadb.org/mariadb-vector-how-it-works-part-ii/</link>
      <pubDate>Thu, 26 Mar 2026 07:34:29 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.org/">MariaDB.org</source>
      <description><![CDATA[<p>In the first post of this series, I’ve described how the vector index is stored in a table and how it achieves full transactional behavior and ACID properties compatible with the storage engine of the table the user created. …<br />
Continue reading \"MariaDB Vector: How it works. Part II\"<br />
The post MariaDB Vector: How it works. Part II appeared first on MariaDB.org.</p>
<p>The post <a rel="nofollow" href="https://mariadb.org/mariadb-vector-how-it-works-part-ii/">MariaDB Vector: How it works. Part II</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>In the first post of this series, I&rsquo;ve described how the vector index is stored in a table and how it achieves full transactional behavior and ACID properties compatible with the storage engine of the table the user created. &hellip; </p>
<p class="link-more"><a href="https://mariadb.org/mariadb-vector-how-it-works-part-ii/" class="more-link">Continue reading<span class="screen-reader-text"> &ldquo;MariaDB Vector: How it works. Part II&rdquo;</span></a></p>
<p>The post <a rel="nofollow" href="https://mariadb.org/mariadb-vector-how-it-works-part-ii/">MariaDB Vector: How it works. Part II</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>

<p>The post <a rel="nofollow" href="https://mariadb.org/mariadb-vector-how-it-works-part-ii/">MariaDB Vector: How it works. Part II</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>Datography Joins MariaDB Foundation as Silver Sponsor</title>
      <link>https://mariadb.org/datography-joins-mariadb-foundation-as-silver-sponsor/</link>
      <pubDate>Wed, 25 Mar 2026 14:42:02 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.org/">MariaDB.org</source>
      <description><![CDATA[<p>We are pleased to welcome Datography as a Silver Sponsor of the MariaDB Foundation.<br />
Datography focuses on helping organizations understand, map, and manage complex data environments. …<br />
Continue reading \"Datography Joins MariaDB Foundation as Silver Sponsor\"<br />
The post Datography Joins MariaDB Foundation as Silver Sponsor appeared first on MariaDB.org.</p>
<p>The post <a rel="nofollow" href="https://mariadb.org/datography-joins-mariadb-foundation-as-silver-sponsor/">Datography Joins MariaDB Foundation as Silver Sponsor</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>We are pleased to welcome <a href="https://www.datography.net/">Datography</a> as a Silver Sponsor of the MariaDB Foundation.<br>
Datography focuses on helping organizations understand, map, and manage complex data environments. &hellip; </p>
<p class="link-more"><a href="https://mariadb.org/datography-joins-mariadb-foundation-as-silver-sponsor/" class="more-link">Continue reading<span class="screen-reader-text"> &ldquo;Datography Joins MariaDB Foundation as Silver Sponsor&rdquo;</span></a></p>
<p>The post <a rel="nofollow" href="https://mariadb.org/datography-joins-mariadb-foundation-as-silver-sponsor/">Datography Joins MariaDB Foundation as Silver Sponsor</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>

<p>The post <a rel="nofollow" href="https://mariadb.org/datography-joins-mariadb-foundation-as-silver-sponsor/">Datography Joins MariaDB Foundation as Silver Sponsor</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>MariaDB Keeps Climbing: Community, Adoption, and Momentum</title>
      <link>https://mariadb.org/mariadb-keeps-climbing-community-adoption-and-momentum/</link>
      <pubDate>Wed, 25 Mar 2026 09:59:41 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.org/">MariaDB.org</source>
      <description><![CDATA[<p>If you’ve been around the MariaDB community for a while, you can probably feel it already: things are moving in the right direction.<br />
And no, I’m not talking about one vanity metric, one lucky spike, or one noisy social post. …<br />
Continue reading \"MariaDB Keeps Climbing: Community, Adoption, and Momentum\"<br />
The post MariaDB Keeps Climbing: Community, Adoption, and Momentum appeared first on MariaDB.org.</p>
<p>The post <a rel="nofollow" href="https://mariadb.org/mariadb-keeps-climbing-community-adoption-and-momentum/">MariaDB Keeps Climbing: Community, Adoption, and Momentum</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>If you&rsquo;ve been around the MariaDB community for a while, you can probably feel it already: things are moving in the right direction.<br>
And no, I&rsquo;m not talking about one vanity metric, one lucky spike, or one noisy social post. &hellip; </p>
<p class="link-more"><a href="https://mariadb.org/mariadb-keeps-climbing-community-adoption-and-momentum/" class="more-link">Continue reading<span class="screen-reader-text"> &ldquo;MariaDB Keeps Climbing: Community, Adoption, and Momentum&rdquo;</span></a></p>
<p>The post <a rel="nofollow" href="https://mariadb.org/mariadb-keeps-climbing-community-adoption-and-momentum/">MariaDB Keeps Climbing: Community, Adoption, and Momentum</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>

<p>The post <a rel="nofollow" href="https://mariadb.org/mariadb-keeps-climbing-community-adoption-and-momentum/">MariaDB Keeps Climbing: Community, Adoption, and Momentum</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>The Agentic Era: Why Infrastructure is the New Innovation Frontier</title>
      <link>https://mariadb.com/resources/blog/the-agentic-era-why-infrastructure-is-the-new-innovation-frontier/</link>
      <pubDate>Tue, 24 Mar 2026 13:02:04 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.com/">MariaDB</source>
      <description><![CDATA[<p>Eighteen months ago, when I joined MariaDB, the industry was already feeling the first tremors of the AI boom. While […]</p>
<p>The post <a rel="nofollow" href="https://mariadb.com/resources/blog/the-agentic-era-why-infrastructure-is-the-new-innovation-frontier/">The Agentic Era: Why Infrastructure is the New Innovation Frontier</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>Eighteen months ago, when I joined MariaDB, the industry was already feeling the first tremors of the AI boom. While the world focused on the &ldquo;froth&rdquo; &ndash; the flashy consumer apps and chatbots &ndash; the enterprise conversation was stuck on adoption: Will people use it? Will they trust it? Today, we know the answer is a resounding &ldquo;yes.&rdquo; Employees and management alike are eager to leverage AI.</p>
<p><a href="https://mariadb.com/resources/blog/the-agentic-era-why-infrastructure-is-the-new-innovation-frontier/" rel="nofollow">Source</a></p>

<p>The post <a rel="nofollow" href="https://mariadb.com/resources/blog/the-agentic-era-why-infrastructure-is-the-new-innovation-frontier/">The Agentic Era: Why Infrastructure is the New Innovation Frontier</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>MariaDB 13.0 Preview Now Available</title>
      <link>https://mariadb.org/mariadb-13-0-preview-now-available/</link>
      <pubDate>Tue, 24 Mar 2026 12:49:52 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.org/">MariaDB.org</source>
      <description><![CDATA[<p>We are pleased to announce the availability of a preview of the MariaDB 13.0 series. MariaDB 13.0 is a preview rolling release, published on 23 March 2026, and it continues the work started in 12.3 while adding a solid set of entirely new features. …<br />
Continue reading \"MariaDB 13.0 Preview Now Available\"<br />
The post MariaDB 13.0 Preview Now Available appeared first on MariaDB.org.</p>
<p>The post <a rel="nofollow" href="https://mariadb.org/mariadb-13-0-preview-now-available/">MariaDB 13.0 Preview Now Available</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>We are pleased to announce the availability of a preview of the <a href="https://mariadb.com/docs/release-notes/community-server/13.0/mariadb-13.0-changes-and-improvements">MariaDB 13.0</a> series. MariaDB 13.0 is a preview rolling release, published on 23 March 2026, and it continues the work started in 12.3 while adding a solid set of entirely new features. &hellip; </p>
<p class="link-more"><a href="https://mariadb.org/mariadb-13-0-preview-now-available/" class="more-link">Continue reading<span class="screen-reader-text"> &ldquo;MariaDB 13.0 Preview Now Available&rdquo;</span></a></p>
<p>The post <a rel="nofollow" href="https://mariadb.org/mariadb-13-0-preview-now-available/">MariaDB 13.0 Preview Now Available</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>

<p>The post <a rel="nofollow" href="https://mariadb.org/mariadb-13-0-preview-now-available/">MariaDB 13.0 Preview Now Available</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
      <item>
      <title>DBaasNow Joins MariaDB Foundation as Silver Sponsor</title>
      <link>https://mariadb.org/dbaasnow-joins-mariadb-foundation-as-silver-sponsor/</link>
      <pubDate>Tue, 24 Mar 2026 07:05:43 +0000</pubDate>
      <dc:creator></dc:creator>
      <guid isPermaLink="false"></guid>
      <source url="https://mariadb.org/">MariaDB.org</source>
      <description><![CDATA[<p>We are pleased to welcome DBaasNow as a Silver Sponsor of the MariaDB Foundation.<br />
As the MariaDB ecosystem continues to expand across cloud, hybrid, and on-premise environments, the need for consistent, reliable, and scalable database operations has never been more important. …<br />
Continue reading \"DBaasNow Joins MariaDB Foundation as Silver Sponsor\"<br />
The post DBaasNow Joins MariaDB Foundation as Silver Sponsor appeared first on MariaDB.org.</p>
<p>The post <a rel="nofollow" href="https://mariadb.org/dbaasnow-joins-mariadb-foundation-as-silver-sponsor/">DBaasNow Joins MariaDB Foundation as Silver Sponsor</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></description>
      <content:encoded><![CDATA[<p>We are pleased to welcome <a href="https://dbaasnow.com/welcome/">DBaasNow </a>as a Silver Sponsor of the MariaDB Foundation.<br>
As the MariaDB ecosystem continues to expand across cloud, hybrid, and on-premise environments, the need for consistent, reliable, and scalable database operations has never been more important. &hellip; </p>
<p class="link-more"><a href="https://mariadb.org/dbaasnow-joins-mariadb-foundation-as-silver-sponsor/" class="more-link">Continue reading<span class="screen-reader-text"> &ldquo;DBaasNow Joins MariaDB Foundation as Silver Sponsor&rdquo;</span></a></p>
<p>The post <a rel="nofollow" href="https://mariadb.org/dbaasnow-joins-mariadb-foundation-as-silver-sponsor/">DBaasNow Joins MariaDB Foundation as Silver Sponsor</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>

<p>The post <a rel="nofollow" href="https://mariadb.org/dbaasnow-joins-mariadb-foundation-as-silver-sponsor/">DBaasNow Joins MariaDB Foundation as Silver Sponsor</a> appeared first on <a rel="nofollow" href="https://mariadb.org">MariaDB.org</a>.</p>
]]></content:encoded>
                </item>
    </channel>
</rss>