diff --git a/meta-oe/recipes-dbs/mysql/mariadb.inc b/meta-oe/recipes-dbs/mysql/mariadb.inc
index c10b0ac9a5..1cf90c8f93 100644
--- a/meta-oe/recipes-dbs/mysql/mariadb.inc
+++ b/meta-oe/recipes-dbs/mysql/mariadb.inc
@@ -26,6 +26,7 @@ SRC_URI = "https://archive.mariadb.org/${BP}/source/${BP}.tar.gz \
            file://0001-support-reproducible-builds.patch \
            file://0001-storage-mroonga-CMakeLists.txt-fix-reproducible-buil.patch \
            file://c21bb11be28ae9b2432b2a661bf38a197cf9514d.patch \
+           file://0001-MDEV-40287-AES_ENCRYPT-and-KDF-return-NULL-with-Open.patch \
           "
 SRC_URI[sha256sum] = "5ab7883db519bfcebfdd2aac09bc5544a12ce328f39edd46d0bf01690615ef6c"
 
diff --git a/meta-oe/recipes-dbs/mysql/mariadb/0001-MDEV-40287-AES_ENCRYPT-and-KDF-return-NULL-with-Open.patch b/meta-oe/recipes-dbs/mysql/mariadb/0001-MDEV-40287-AES_ENCRYPT-and-KDF-return-NULL-with-Open.patch
new file mode 100644
index 0000000000..af9c596962
--- /dev/null
+++ b/meta-oe/recipes-dbs/mysql/mariadb/0001-MDEV-40287-AES_ENCRYPT-and-KDF-return-NULL-with-Open.patch
@@ -0,0 +1,290 @@
+From c66dc27030154edf175e049473159c789abb9a43 Mon Sep 17 00:00:00 2001
+From: Vladislav Vaintroub <vvaintroub@gmail.com>
+Date: Wed, 9 Sep 2026 01:44:02 +0200
+Subject: [PATCH] MDEV-40287 AES_ENCRYPT() and KDF() return NULL with OpenSSL
+ 4.0
+
+MyCTX used an EVP_CIPHER_CTX in a stack buffer instead of allocating it
+with EVP_CIPHER_CTX_new(). OpenSSL 4.0 rejects a context that was not
+created that way for ciphers that use an IV: EVP_CipherInit_ex() fails
+with "invalid iv length", so AES_ENCRYPT() and KDF() in CBC/CTR/GCM
+modes return NULL. ECB has no IV and still works, which is why only the
+non-ECB modes broke.
+
+Fix:
+Allocate the context with EVP_CIPHER_CTX_new()/EVP_CIPHER_CTX_free().
+Also remove check_openssl_compatibility() and the EVP_CIPHER_CTX_SIZE
+and EVP_CIPHER_CTX_init macros.
+
+Verified against OpenSSL 4.0.1: the mysys aes-t test fails on the
+CBC/CTR/GCM cases with the stack buffer and passes with
+EVP_CIPHER_CTX_new().
+
+No visible performance degradation: the extra allocation costs
+~12 ns/call (WolfSSL) and ~30 ns (OpenSSL) on Windows at a 30-byte
+payload, nothing at 16 KB, and nothing on Linux/glibc; sysbench OLTP
+over encrypted tables and redo log is unchanged.
+
+Assisted-by: Claude:claude-opus-4-8
+
+[Squashed with the "fixup!" commit 36c6e66b29bb from the same PR, which
+destroys the context in my_aes_crypt_init() when init() fails so the
+heap allocated EVP_CIPHER_CTX is not leaked. Rebased to 11.4.12.]
+
+Upstream-Status: Submitted [https://github.com/MariaDB/server/pull/5652]
+Signed-off-by: Khem Raj <khem.raj@oss.qualcomm.com>
+---
+diff -urN a/include/ssl_compat.h b/include/ssl_compat.h
+--- a/include/ssl_compat.h
++++ b/include/ssl_compat.h
+@@ -24,12 +24,9 @@
+ #define HAVE_OPENSSL11 1
+ #define SSL_LIBRARY OpenSSL_version(OPENSSL_VERSION)
+ #define ERR_remove_state(X) ERR_clear_error()
+-#define EVP_CIPHER_CTX_SIZE 200
+ #define EVP_MD_CTX_SIZE 80
+ #undef EVP_MD_CTX_init
+ #define EVP_MD_CTX_init(X) do { memset((X), 0, EVP_MD_CTX_SIZE); EVP_MD_CTX_reset(X); } while(0)
+-#undef EVP_CIPHER_CTX_init
+-#define EVP_CIPHER_CTX_init(X) do { memset((X), 0, EVP_CIPHER_CTX_SIZE); EVP_CIPHER_CTX_reset(X); } while(0)
+ 
+ /*
+   Macros below are deprecated. OpenSSL 1.1 may define them or not,
+@@ -83,7 +80,6 @@
+ #endif
+ 
+ #define EVP_CIPHER_CTX_encrypting(ctx)  ((ctx)->encrypt)
+-#define EVP_CIPHER_CTX_SIZE             sizeof(EVP_CIPHER_CTX)
+ 
+ #ifndef HAVE_WOLFSSL
+ #define OPENSSL_init_ssl(X,Y)           SSL_library_init()
+@@ -97,13 +93,3 @@
+ #ifndef TLS1_3_VERSION
+ #define SSL_CTX_set_ciphersuites(X,Y) 0
+ #endif
+-
+-#ifdef	__cplusplus
+-extern "C" {
+-#endif /* __cplusplus */
+-
+-int check_openssl_compatibility();
+-
+-#ifdef	__cplusplus
+-}
+-#endif
+diff -urN a/mysys_ssl/CMakeLists.txt b/mysys_ssl/CMakeLists.txt
+--- a/mysys_ssl/CMakeLists.txt
++++ b/mysys_ssl/CMakeLists.txt
+@@ -28,7 +28,6 @@
+     my_sha384.cc
+     my_sha512.cc
+     my_md5.cc
+-    openssl.c
+    )
+ 
+ SET(MYSYS_SSL_SOURCES
+diff -urN a/mysys_ssl/my_crypt.cc b/mysys_ssl/my_crypt.cc
+--- a/mysys_ssl/my_crypt.cc
++++ b/mysys_ssl/my_crypt.cc
+@@ -27,29 +27,18 @@
+ 
+ #include <my_crypt.h>
+ #include <ssl_compat.h>
+-#include <cstdint>
+-
+-#define CTX_ALIGN 16
+ 
+ class MyCTX
+ {
+ public:
+-  char ctx_buf[EVP_CIPHER_CTX_SIZE + CTX_ALIGN];
+   EVP_CIPHER_CTX* ctx;
+   MyCTX()
+   {
+-#if CTX_ALIGN > 0
+-    uintptr_t p= ((uintptr_t)ctx_buf + (CTX_ALIGN - 1)) & ~(CTX_ALIGN - 1);
+-    ctx = reinterpret_cast<EVP_CIPHER_CTX*>(p);
+-#else
+-    ctx = (EVP_CIPHER_CTX*)ctx_buf;
+-#endif
+-
+-    EVP_CIPHER_CTX_init(ctx);
++    ctx= EVP_CIPHER_CTX_new();
+   }
+   virtual ~MyCTX()
+   {
+-    EVP_CIPHER_CTX_reset(ctx);
++    EVP_CIPHER_CTX_free(ctx);
+     ERR_remove_state(0);
+   }
+ 
+@@ -57,6 +46,8 @@
+                    uint klen, const uchar *iv, uint ivlen)
+   {
+     compile_time_assert(MY_AES_CTX_SIZE >= sizeof(MyCTX));
++    if (unlikely(!ctx))
++      return MY_AES_OPENSSL_ERROR;
+     if (unlikely(!cipher))
+       return MY_AES_BAD_KEYSIZE;
+ 
+@@ -115,9 +106,11 @@
+     DBUG_ASSERT(ivlen == 0 || ivlen == sizeof(oiv));
+ 
+     int res= MyCTX::init(cipher, encrypt, key, klen, iv, ivlen);
++    if (res)
++      return res;
+ 
+     EVP_CIPHER_CTX_set_padding(ctx, 0);
+-    return res;
++    return MY_AES_OK;
+   }
+ 
+   /** Update last partial source block, stored in source_tail array. */
+@@ -213,10 +206,12 @@
+   {
+     compile_time_assert(MY_AES_CTX_SIZE >= sizeof(MyCTX_gcm));
+     int res= MyCTX::init(cipher, encrypt, key, klen, iv, ivlen);
++    if (res)
++      return res;
+     int real_ivlen= EVP_CIPHER_CTX_iv_length(ctx);
+     aad= iv + real_ivlen;
+     aadlen= ivlen - real_ivlen;
+-    return res;
++    return MY_AES_OK;
+   }
+ 
+   int update(const uchar *src, uint slen, uchar *dst, uint *dlen) override
+@@ -298,8 +293,11 @@
+     new (ctx) MyCTX_nopad();
+   else
+     new (ctx) MyCTX();
+-  return ((MyCTX*)ctx)->init(ciphers[mode](klen), flags & 1,
+-                             key, klen, iv, ivlen);
++  int res= ((MyCTX*)ctx)->init(ciphers[mode](klen), flags & 1,
++                               key, klen, iv, ivlen);
++  if (res)
++    ((MyCTX*)ctx)->~MyCTX();
++  return res;
+ }
+ 
+ int my_aes_crypt_update(void *ctx, const uchar *src, uint slen,
+diff -urN a/mysys_ssl/openssl.c b/mysys_ssl/openssl.c
+--- a/mysys_ssl/openssl.c
++++ /dev/null
+@@ -1,98 +0,0 @@
+-/*
+- Copyright (c) 2017, MariaDB Corporation.
+-
+- This program is free software; you can redistribute it and/or modify
+- it under the terms of the GNU General Public License as published by
+- the Free Software Foundation; version 2 of the License.
+-
+- This program is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- GNU General Public License for more details.
+-
+- You should have received a copy of the GNU General Public License
+- along with this program; if not, write to the Free Software
+- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
+-
+-#include <my_global.h>
+-#include <openssl/evp.h>
+-#include <ssl_compat.h>
+-
+-/*
+-  The check is only done for OpenSSL 1.1.x.
+-  It could run for OpenSSL 1.0.x but it doesn't make much sense
+-  and it hits this bug:
+-  https://bugs.launchpad.net/ubuntu/+source/openssl/+bug/1594748
+-*/
+-
+-#ifndef HAVE_OPENSSL11
+-int check_openssl_compatibility()
+-{
+-  return 0;
+-}
+-#else
+-#include <openssl/evp.h>
+-
+-static uint testing;
+-static size_t alloc_size, alloc_count;
+-
+-static void *coc_malloc(size_t size
+-#ifndef LIBRESSL_VERSION_NUMBER
+-                        , const char *f __attribute__((unused)),
+-                        int l __attribute__((unused))
+-#endif
+-)
+-{
+-  if (unlikely(testing))
+-  {
+-    alloc_size+= size;
+-    alloc_count++;
+-  }
+-  return malloc(size);
+-}
+-
+-static void *coc_realloc(void *addr, size_t num
+-#ifndef LIBRESSL_VERSION_NUMBER
+-                         , const char *file __attribute__((unused)),
+-                         int line __attribute__((unused))
+-#endif
+-)
+-{
+-  return realloc(addr, num);
+-}
+-
+-static void coc_free(void *addr
+-#ifndef LIBRESSL_VERSION_NUMBER
+-                     , const char *file __attribute__((unused)),
+-                     int line __attribute__((unused))
+-#endif
+-)
+-{
+-  free(addr);
+-}
+-
+-int check_openssl_compatibility()
+-{
+-  EVP_CIPHER_CTX *evp_ctx;
+-  EVP_MD_CTX     *md5_ctx;
+-
+-  if (!CRYPTO_set_mem_functions(coc_malloc, coc_realloc, coc_free))
+-    return 0;
+-
+-  testing= 1;
+-  alloc_size= alloc_count= 0;
+-  evp_ctx= EVP_CIPHER_CTX_new();
+-  EVP_CIPHER_CTX_free(evp_ctx);
+-  if (alloc_count != 1 || !alloc_size || alloc_size > EVP_CIPHER_CTX_SIZE)
+-    return 1;
+-
+-  alloc_size= alloc_count= 0;
+-  md5_ctx= EVP_MD_CTX_new();
+-  EVP_MD_CTX_free(md5_ctx);
+-  if (alloc_count != 1 || !alloc_size || alloc_size > EVP_MD_CTX_SIZE)
+-    return 1;
+-
+-  testing= 0;
+-  return 0;
+-}
+-#endif
+diff -urN a/sql/mysqld.cc b/sql/mysqld.cc
+--- a/sql/mysqld.cc
++++ b/sql/mysqld.cc
+@@ -3948,14 +3948,6 @@
+     exit(1);
+   }
+ 
+-#ifdef HAVE_OPENSSL
+-  if (check_openssl_compatibility())
+-  {
+-    sql_print_error("Incompatible OpenSSL version. Cannot continue...");
+-    exit(1);
+-  }
+-#endif
+-
+   if (init_thread_environment() || mysql_init_variables())
+     exit(1);
+ 
