diff --git a/include/_mgp.hpp b/include/_mgp.hpp
index 8b67bc36a..3091eac8e 100644
--- a/include/_mgp.hpp
+++ b/include/_mgp.hpp
@@ -851,4 +851,6 @@ inline void func_result_set_value(mgp_func_result *res, mgp_value *value, mgp_me
   MgInvokeVoid(mgp_func_result_set_value, res, value, memory);
 }
 
+inline void execute_query(mgp_graph *graph, const char *query) { MgInvokeVoid(mgp_execute_query, graph, query); }
+
 }  // namespace mgp
diff --git a/include/mg_procedure.h b/include/mg_procedure.h
index 93ef241d8..1b8641fb1 100644
--- a/include/mg_procedure.h
+++ b/include/mg_procedure.h
@@ -1,4 +1,4 @@
-// Copyright 2023 Memgraph Ltd.
+// Copyright 2024 Memgraph Ltd.
 //
 // Use of this software is governed by the Business Source License
 // included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -1800,6 +1800,9 @@ enum mgp_error mgp_func_result_set_error_msg(struct mgp_func_result *result, con
 /// mgp_func_result.
 enum mgp_error mgp_func_result_set_value(struct mgp_func_result *result, struct mgp_value *value,
                                          struct mgp_memory *memory);
+
+enum mgp_error mgp_execute_query(mgp_graph *graph, const char *query);
+
 /// @}
 
 #ifdef __cplusplus
diff --git a/include/mgp.hpp b/include/mgp.hpp
index 3f7ed591e..b8adb2ea3 100644
--- a/include/mgp.hpp
+++ b/include/mgp.hpp
@@ -1,4 +1,4 @@
-// Copyright 2023 Memgraph Ltd.
+// Copyright 2024 Memgraph Ltd.
 //
 // Use of this software is governed by the Business Source License
 // included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -93,6 +93,7 @@ class Relationship;
 struct MapItem;
 class Duration;
 class Value;
+class QueryExecution;
 
 struct StealType {};
 inline constexpr StealType steal{};
@@ -1550,6 +1551,15 @@ class Return {
   mgp_type *GetMGPType() const;
 };
 
+class QueryExecution {
+ public:
+  QueryExecution(mgp_graph *graph);
+  void ExecuteQuery(std::string_view query);
+
+ private:
+  mgp_graph *graph_;
+};
+
 enum class ProcedureType : uint8_t {
   Read,
   Write,
@@ -4286,6 +4296,10 @@ inline mgp_type *Return::GetMGPType() const {
   return util::ToMGPType(type_);
 }
 
+inline QueryExecution::QueryExecution(mgp_graph *graph) : graph_(graph) {}
+
+inline void QueryExecution::ExecuteQuery(std::string_view query) const { mgp::execute_query(graph_, query.data()); }
+
 // do not enter
 namespace detail {
 inline void AddParamsReturnsToProc(mgp_proc *proc, std::vector<Parameter> &parameters,
diff --git a/src/query/context.hpp b/src/query/context.hpp
index f1522053c..288505c7d 100644
--- a/src/query/context.hpp
+++ b/src/query/context.hpp
@@ -72,6 +72,12 @@ inline std::vector<storage::LabelId> NamesToLabels(const std::vector<std::string
   return labels;
 }
 
+struct UserExecutionContextInfo {
+  enum class UserMode { NONE, USER, ROLE };
+  UserMode mode;
+  std::string name;
+};
+
 struct ExecutionContext {
   DbAccessor *db_accessor{nullptr};
   SymbolTable symbol_table;
@@ -86,6 +92,7 @@ struct ExecutionContext {
   TriggerContextCollector *trigger_context_collector{nullptr};
   FrameChangeCollector *frame_change_collector{nullptr};
   std::shared_ptr<utils::AsyncTimer> timer;
+  UserExecutionContextInfo user_info;
 #ifdef MG_ENTERPRISE
   std::unique_ptr<FineGrainedAuthChecker> auth_checker{nullptr};
 #endif
diff --git a/src/query/interpreter.cpp b/src/query/interpreter.cpp
index 0cc0f182a..4395da387 100644
--- a/src/query/interpreter.cpp
+++ b/src/query/interpreter.cpp
@@ -1720,6 +1720,13 @@ PullPlan::PullPlan(const std::shared_ptr<PlanWrapper> plan, const Parameters &pa
   ctx_.evaluation_context.parameters = parameters;
   ctx_.evaluation_context.properties = NamesToProperties(plan->ast_storage().properties_, dba);
   ctx_.evaluation_context.labels = NamesToLabels(plan->ast_storage().labels_, dba);
+  if (!user_or_role) {
+    ctx_.user_info = {.mode = UserExecutionContextInfo::UserMode::NONE, .name = ""};
+  } else {
+    ctx_.user_info = {.mode = user_or_role->username() ? UserExecutionContextInfo::UserMode::USER
+                                                       : UserExecutionContextInfo::UserMode::ROLE,
+                      .name = user_or_role->key()};
+  }
 #ifdef MG_ENTERPRISE
   if (license::global_license_checker.IsEnterpriseValidFast() && user_or_role && *user_or_role && dba) {
     // Create only if an explicit user is defined
diff --git a/src/query/interpreter_context.hpp b/src/query/interpreter_context.hpp
index 1124ab3fd..1849431f5 100644
--- a/src/query/interpreter_context.hpp
+++ b/src/query/interpreter_context.hpp
@@ -27,6 +27,7 @@
 #include "storage/v2/transaction.hpp"
 #include "system/state.hpp"
 #include "system/system.hpp"
+#include "utils/exceptions.hpp"
 #include "utils/gatekeeper.hpp"
 #include "utils/skip_list.hpp"
 #include "utils/spin_lock.hpp"
@@ -56,6 +57,11 @@ struct QueryUserOrRole;
 struct InterpreterContext {
   static InterpreterContext *instance;
 
+  static InterpreterContext *getInstance() {
+    MG_ASSERT(instance == nullptr, "Interpreter context has not been initialized!");
+    return instance;
+  }
+
   static InterpreterContext *getInstance(InterpreterConfig interpreter_config, dbms::DbmsHandler *dbms_handler,
                                          replication::ReplicationState *rs, memgraph::system::System &system,
 #ifdef MG_ENTERPRISE
diff --git a/src/query/procedure/mg_procedure_impl.cpp b/src/query/procedure/mg_procedure_impl.cpp
index d6ce3c7b7..4b2d8d1c6 100644
--- a/src/query/procedure/mg_procedure_impl.cpp
+++ b/src/query/procedure/mg_procedure_impl.cpp
@@ -27,7 +27,10 @@
 #include "mg_procedure.h"
 #include "module.hpp"
 #include "query/db_accessor.hpp"
+#include "query/discard_value_stream.hpp"
 #include "query/frontend/ast/ast.hpp"
+#include "query/interpreter.hpp"
+#include "query/interpreter_context.hpp"
 #include "query/procedure/cypher_types.hpp"
 #include "query/procedure/fmt.hpp"
 #include "query/procedure/mg_procedure_helpers.hpp"
@@ -4021,3 +4024,27 @@ mgp_error mgp_untrack_current_thread_allocations(mgp_graph *graph) {
     std::visit([](auto *db_accessor) -> void { db_accessor->UntrackCurrentThreadAllocations(); }, graph->impl);
   });
 }
+
+mgp_error mgp_execute_query(mgp_graph *graph, const char *query) {
+  return WrapExceptions([&]() {
+    auto query_string = std::string(query);
+    auto user_info = graph->ctx->user_info;
+    auto *instance = memgraph::query::InterpreterContext::getInstance();
+
+    memgraph::query::Interpreter interpreter(instance);
+
+    instance->interpreters.WithLock([&interpreter](auto &interpreters) { interpreters.insert(&interpreter); });
+
+    memgraph::utils::OnScopeExit erase_interpreter([&] {
+      instance->interpreters.WithLock([&interpreter](auto &interpreters) { interpreters.erase(&interpreter); });
+    });
+
+    memgraph::query::AllowEverythingAuthChecker tmp_auth_checker;
+    auto tmp_user = tmp_auth_checker.GenQueryUser(std::nullopt, std::nullopt);
+    interpreter.SetUser(tmp_user);
+
+    auto results = interpreter.Prepare(query_string, {}, {});
+    memgraph::query::DiscardValueResultStream stream;
+    interpreter.Pull(&stream, {}, results.qid);
+  });
+}
diff --git a/src/query/procedure/mg_procedure_impl.hpp b/src/query/procedure/mg_procedure_impl.hpp
index 17cac4eca..e3af8b863 100644
--- a/src/query/procedure/mg_procedure_impl.hpp
+++ b/src/query/procedure/mg_procedure_impl.hpp
@@ -1,4 +1,4 @@
-// Copyright 2023 Memgraph Ltd.
+// Copyright 2024 Memgraph Ltd.
 //
 // Use of this software is governed by the Business Source License
 // included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -24,6 +24,7 @@
 #include "query/context.hpp"
 #include "query/db_accessor.hpp"
 #include "query/frontend/ast/ast.hpp"
+
 #include "query/procedure/cypher_type_ptr.hpp"
 #include "query/typed_value.hpp"
 #include "storage/v2/view.hpp"
@@ -993,3 +994,9 @@ struct mgp_messages {
 bool ContainsDeleted(const mgp_value *val);
 
 memgraph::query::TypedValue ToTypedValue(const mgp_value &val, memgraph::utils::MemoryResource *memory);
+
+struct mgp_query_execution {
+  explicit mgp_query_execution(){};
+
+  ~mgp_query_execution() = default;
+};