diff --git a/src/xrt/state_trackers/CMakeLists.txt b/src/xrt/state_trackers/CMakeLists.txt
index 51f46b89faac00a5d12e2eb4614898fb48cfe9e1..7b2b625633576969d2de3e13ce3135c196160246 100644
--- a/src/xrt/state_trackers/CMakeLists.txt
+++ b/src/xrt/state_trackers/CMakeLists.txt
@@ -23,6 +23,7 @@ set(OXR_SOURCE_FILES
 	oxr/oxr_instance.c
 	oxr/oxr_logger.cpp
 	oxr/oxr_logger.h
+	oxr/oxr_messenger.c
 	oxr/oxr_objects.h
 	oxr/oxr_session.c
 	oxr/oxr_session_gl.c
diff --git a/src/xrt/state_trackers/oxr/oxr_api_debug.c b/src/xrt/state_trackers/oxr/oxr_api_debug.c
index 0d3f777d920a0da0a82f9c682a72a427323c686f..744c95f84dba325f66f3ce17fa2ccd1bd99475bd 100644
--- a/src/xrt/state_trackers/oxr/oxr_api_debug.c
+++ b/src/xrt/state_trackers/oxr/oxr_api_debug.c
@@ -35,11 +35,23 @@ oxr_xrCreateDebugUtilsMessengerEXT(
     XrDebugUtilsMessengerEXT* messenger)
 {
 	struct oxr_instance* inst;
+	struct oxr_debug_messenger* mssngr;
 	struct oxr_logger log;
 	OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst,
 	                                 "xrCreateDebugUtilsMessengerEXT");
 
-	return oxr_error(&log, XR_ERROR_RUNTIME_FAILURE, " not implemented");
+	OXR_VERIFY_ARG_TYPE_AND_NULL(
+	    &log, createInfo, XR_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT);
+	OXR_VERIFY_ARG_NOT_NULL(&log, messenger);
+
+	XrResult ret = oxr_create_messenger(&log, inst, createInfo, &mssngr);
+	if (ret != XR_SUCCESS) {
+		return ret;
+	}
+
+	*messenger = oxr_messenger_to_openxr(mssngr);
+
+	return XR_SUCCESS;
 }
 
 XrResult
@@ -50,7 +62,7 @@ oxr_xrDestroyDebugUtilsMessengerEXT(XrDebugUtilsMessengerEXT messenger)
 	OXR_VERIFY_MESSENGER_AND_INIT_LOG(&log, messenger, mssngr,
 	                                  "xrDestroyDebugUtilsMessengerEXT");
 
-	return oxr_error(&log, XR_ERROR_RUNTIME_FAILURE, " not implemented");
+	return oxr_handle_destroy(&log, &mssngr->handle);
 }
 
 XrResult
@@ -65,7 +77,8 @@ oxr_xrSubmitDebugUtilsMessageEXT(
 	OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst,
 	                                 "xrSubmitDebugUtilsMessageEXT");
 
-	return oxr_error(&log, XR_ERROR_RUNTIME_FAILURE, " not implemented");
+	oxr_warn(&log, " not fully implemented");
+	return XR_SUCCESS;
 }
 
 XrResult
diff --git a/src/xrt/state_trackers/oxr/oxr_messenger.c b/src/xrt/state_trackers/oxr/oxr_messenger.c
new file mode 100644
index 0000000000000000000000000000000000000000..f8464b348357c965a1eb91f55acdd86fc87b2ceb
--- /dev/null
+++ b/src/xrt/state_trackers/oxr/oxr_messenger.c
@@ -0,0 +1,81 @@
+// Copyright 2018-2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Holds debug utils/messenger related functions.
+ * @author Ryan Pavlik <ryan.pavlik@collabora.com>
+ * @ingroup oxr_main
+ */
+
+#include <stdlib.h>
+
+#include "util/u_debug.h"
+#include "util/u_misc.h"
+
+#include "oxr_objects.h"
+#include "oxr_logger.h"
+#include "oxr_handle.h"
+
+#ifdef XR_EXT_debug_utils
+
+static XrResult
+oxr_messenger_destroy(struct oxr_logger *log, struct oxr_handle_base *hb)
+{
+	struct oxr_debug_messenger *mssngr = (struct oxr_debug_messenger *)hb;
+	struct oxr_instance *inst = mssngr->inst;
+
+	/*
+	 * Instances keep typed pointers to messengers around too.
+	 * Remove ourselves.
+	 */
+	for (size_t i = 0; i < XRT_MAX_HANDLE_CHILDREN; ++i) {
+		if (inst->messengers[i] == mssngr) {
+			inst->messengers[i] = NULL;
+			free(mssngr);
+			return XR_SUCCESS;
+		}
+	}
+	return oxr_error(log, XR_ERROR_RUNTIME_FAILURE,
+	                 " debug messenger not found in parent instance");
+}
+
+//! @todo call into inst to create this instead?
+XrResult
+oxr_create_messenger(struct oxr_logger *log,
+                     struct oxr_instance *inst,
+                     const XrDebugUtilsMessengerCreateInfoEXT *createInfo,
+                     struct oxr_debug_messenger **out_mssngr)
+{
+
+	struct oxr_debug_messenger **parent_slot = NULL;
+	for (size_t i = 0; i < XRT_MAX_HANDLE_CHILDREN; ++i) {
+		if (inst->messengers[i] == NULL) {
+			parent_slot = &(inst->messengers[i]);
+			break;
+		}
+	}
+	if (parent_slot == NULL) {
+		return oxr_error(
+		    log, XR_ERROR_LIMIT_REACHED,
+		    " nstance cannot hold any more debug messengers");
+	}
+
+	struct oxr_debug_messenger *mssngr = NULL;
+	OXR_ALLOCATE_HANDLE_OR_RETURN(log, mssngr, OXR_XR_DEBUG_MESSENGER,
+	                              oxr_messenger_destroy,
+	                              &inst->handle);
+
+	mssngr->inst = inst;
+	mssngr->message_severities = createInfo->messageSeverities;
+	mssngr->message_types = createInfo->messageTypes;
+	mssngr->user_callback = createInfo->userCallback;
+	mssngr->user_data = createInfo->userData;
+
+	*parent_slot = mssngr;
+
+	*out_mssngr = mssngr;
+	return XR_SUCCESS;
+}
+
+
+#endif // XR_EXT_debug_utils
diff --git a/src/xrt/state_trackers/oxr/oxr_objects.h b/src/xrt/state_trackers/oxr/oxr_objects.h
index 3bcf0744b5083d657f098b80bae167604a78bd41..1a611b3bd4b59389d6e4a0cb22cd312cf9a837df 100644
--- a/src/xrt/state_trackers/oxr/oxr_objects.h
+++ b/src/xrt/state_trackers/oxr/oxr_objects.h
@@ -64,6 +64,7 @@ struct oxr_swapchain;
 struct oxr_space;
 struct oxr_action_set;
 struct oxr_action;
+struct oxr_debug_messenger;
 struct oxr_handle_base;
 
 #define XRT_MAX_HANDLE_CHILDREN 256
@@ -291,7 +292,31 @@ oxr_create_swapchain(struct oxr_logger *,
 
 /*
  *
+ * oxr_messenger.c
+ *
+ */
 
+#ifdef XR_EXT_debug_utils
+/*!
+ * To go back to a OpenXR object.
+ */
+XRT_MAYBE_UNUSED static inline XrDebugUtilsMessengerEXT
+oxr_messenger_to_openxr(struct oxr_debug_messenger *mssngr)
+{
+	return (XrDebugUtilsMessengerEXT)mssngr;
+}
+
+XrResult
+oxr_create_messenger(struct oxr_logger *,
+                     struct oxr_instance *inst,
+                     const XrDebugUtilsMessengerCreateInfoEXT *,
+                     struct oxr_debug_messenger **out_mssngr);
+XrResult
+oxr_destroy_messenger(struct oxr_logger *log,
+                      struct oxr_debug_messenger *mssngr);
+#endif // XR_EXT_debug_utils
+/*
+ *
  * oxr_system.c
  *
  */
@@ -524,6 +549,11 @@ struct oxr_instance
 	// Event queue.
 	struct oxr_event *last_event;
 	struct oxr_event *next_event;
+
+#ifdef XR_EXT_debug_utils
+	//! Debug messengers
+	struct oxr_debug_messenger *messengers[XRT_MAX_HANDLE_CHILDREN];
+#endif // XR_EXT_debug_utils
 };
 
 /*!
@@ -660,6 +690,21 @@ struct oxr_debug_messenger
 
 	//! Onwer of this messenger.
 	struct oxr_instance *inst;
+
+#ifdef XR_EXT_debug_utils
+	//! Severities to submit to this messenger
+	XrDebugUtilsMessageSeverityFlagsEXT message_severities;
+
+	//! Types to submit to this messenger
+	XrDebugUtilsMessageTypeFlagsEXT message_types;
+
+	//! Callback function
+	PFN_xrDebugUtilsMessengerCallbackEXT user_callback;
+
+	//! Opaque user data
+	void *XR_MAY_ALIAS user_data;
+
+#endif // XR_EXT_debug_utils
 };
 
 /*!