diff --git a/drivers/common/mlx5/linux/mlx5_common_os.c b/drivers/common/mlx5/linux/mlx5_common_os.c
index b516564b79..0d3e24e04e 100644
--- a/drivers/common/mlx5/linux/mlx5_common_os.c
+++ b/drivers/common/mlx5/linux/mlx5_common_os.c
@@ -744,3 +744,59 @@ mlx5_get_device_guid(const struct rte_pci_addr *dev, uint8_t *guid, size_t len)
 	fclose(id_file);
 	return ret;
 }
+
+/*
+ * Create direct mkey using the kernel ibv_reg_mr API and wrap it with a new
+ * indirect mkey created by the DevX API.
+ * This mkey should be used for DevX commands requesting mkey as a parameter.
+ */
+int
+mlx5_os_wrapped_mkey_create(void *ctx, void *pd, uint32_t pdn, void *addr,
+			    size_t length, struct mlx5_pmd_wrapped_mr *pmd_mr)
+{
+	struct mlx5_klm klm = {
+		.byte_count = length,
+		.address = (uintptr_t)addr,
+	};
+	struct mlx5_devx_mkey_attr mkey_attr = {
+		.pd = pdn,
+		.klm_array = &klm,
+		.klm_num = 1,
+	};
+	struct mlx5_devx_obj *mkey;
+	struct ibv_mr *ibv_mr = mlx5_glue->reg_mr(pd, addr, length,
+						  IBV_ACCESS_LOCAL_WRITE |
+						  (haswell_broadwell_cpu ? 0 :
+						  IBV_ACCESS_RELAXED_ORDERING));
+
+	if (!ibv_mr) {
+		rte_errno = errno;
+		return -rte_errno;
+	}
+	klm.mkey = ibv_mr->lkey;
+	mkey_attr.addr = (uintptr_t)addr;
+	mkey_attr.size = length;
+	mkey = mlx5_devx_cmd_mkey_create(ctx, &mkey_attr);
+	if (!mkey) {
+		claim_zero(mlx5_glue->dereg_mr(ibv_mr));
+		return -rte_errno;
+	}
+	pmd_mr->addr = addr;
+	pmd_mr->len = length;
+	pmd_mr->obj = (void *)ibv_mr;
+	pmd_mr->imkey = mkey;
+	pmd_mr->lkey = mkey->id;
+	return 0;
+}
+
+void
+mlx5_os_wrapped_mkey_destroy(struct mlx5_pmd_wrapped_mr *pmd_mr)
+{
+	if (!pmd_mr)
+		return;
+	if (pmd_mr->imkey)
+		claim_zero(mlx5_devx_cmd_destroy(pmd_mr->imkey));
+	if (pmd_mr->obj)
+		claim_zero(mlx5_glue->dereg_mr(pmd_mr->obj));
+	memset(pmd_mr, 0, sizeof(*pmd_mr));
+}
diff --git a/drivers/common/mlx5/mlx5_common.h b/drivers/common/mlx5/mlx5_common.h
index 744c6a72b3..62109a671a 100644
--- a/drivers/common/mlx5/mlx5_common.h
+++ b/drivers/common/mlx5/mlx5_common.h
@@ -429,4 +429,22 @@ mlx5_mr_mb2mr(struct mlx5_common_device *cdev, struct mlx5_mp_id *mp_id,
 int mlx5_os_open_device(struct mlx5_common_device *cdev, uint32_t classes);
 int mlx5_os_pd_create(struct mlx5_common_device *cdev);
 
+/* mlx5 PMD wrapped MR struct. */
+struct mlx5_pmd_wrapped_mr {
+	uint32_t	     lkey;
+	void		     *addr;
+	size_t		     len;
+	void		     *obj; /* verbs mr object or devx umem object. */
+	void		     *imkey; /* DevX indirect mkey object. */
+};
+
+__rte_internal
+int
+mlx5_os_wrapped_mkey_create(void *ctx, void *pd, uint32_t pdn, void *addr,
+			    size_t length, struct mlx5_pmd_wrapped_mr *pmd_mr);
+
+__rte_internal
+void
+mlx5_os_wrapped_mkey_destroy(struct mlx5_pmd_wrapped_mr *pmd_mr);
+
 #endif /* RTE_PMD_MLX5_COMMON_H_ */
diff --git a/drivers/common/mlx5/version.map b/drivers/common/mlx5/version.map
index 6e17a7b8b8..28d685a7c6 100644
--- a/drivers/common/mlx5/version.map
+++ b/drivers/common/mlx5/version.map
@@ -133,6 +133,9 @@ INTERNAL {
 	mlx5_os_umem_dereg;
 	mlx5_os_umem_reg;
 
+	mlx5_os_wrapped_mkey_create;
+	mlx5_os_wrapped_mkey_destroy;
+
 	mlx5_realloc;
 
 	mlx5_translate_port_name; # WINDOWS_NO_EXPORT
diff --git a/drivers/common/mlx5/windows/mlx5_common_os.c b/drivers/common/mlx5/windows/mlx5_common_os.c
index ea478d7395..0d03344343 100644
--- a/drivers/common/mlx5/windows/mlx5_common_os.c
+++ b/drivers/common/mlx5/windows/mlx5_common_os.c
@@ -390,3 +390,43 @@ mlx5_os_set_reg_mr_cb(mlx5_reg_mr_t *reg_mr_cb, mlx5_dereg_mr_t *dereg_mr_cb)
 	*reg_mr_cb = mlx5_os_reg_mr;
 	*dereg_mr_cb = mlx5_os_dereg_mr;
 }
+
+/*
+ * In Windows, no need to wrap the MR, no known issue for it in kernel.
+ * Use the regular function to create direct MR.
+ */
+int
+mlx5_os_wrapped_mkey_create(void *ctx, void *pd, uint32_t pdn, void *addr,
+			    size_t length, struct mlx5_pmd_wrapped_mr *wpmd_mr)
+{
+	struct mlx5_pmd_mr pmd_mr = {0};
+	int ret = mlx5_os_reg_mr(pd, addr, length, &pmd_mr);
+
+	(void)pdn;
+	(void)ctx;
+	if (ret != 0)
+		return -1;
+	wpmd_mr->addr = addr;
+	wpmd_mr->len = length;
+	wpmd_mr->obj = pmd_mr.obj;
+	wpmd_mr->imkey = pmd_mr.mkey;
+	wpmd_mr->lkey = pmd_mr.mkey->id;
+	return 0;
+}
+
+void
+mlx5_os_wrapped_mkey_destroy(struct mlx5_pmd_wrapped_mr *wpmd_mr)
+{
+	struct mlx5_pmd_mr pmd_mr;
+
+	if (!wpmd_mr)
+		return;
+	pmd_mr.addr = wpmd_mr->addr;
+	pmd_mr.len = wpmd_mr->len;
+	pmd_mr.obj = wpmd_mr->obj;
+	pmd_mr.mkey = wpmd_mr->imkey;
+	pmd_mr.lkey = wpmd_mr->lkey;
+	mlx5_os_dereg_mr(&pmd_mr);
+	memset(wpmd_mr, 0, sizeof(*wpmd_mr));
+}
+
