diff --git a/doc/17-language-reference.md b/doc/17-language-reference.md
index cfcb54c76..4c0f76085 100644
--- a/doc/17-language-reference.md
+++ b/doc/17-language-reference.md
@@ -566,6 +566,28 @@ ICINGA2\_RLIMIT\_FILES |**Read-write.** Defines the resource limit for `RLIM
ICINGA2\_RLIMIT\_PROCESSES |**Read-write.** Defines the resource limit for `RLIMIT_NPROC` that should be set at start-up. Value cannot be set lower than the default `16 * 1024`. 0 disables the setting. Set in Icinga 2 sysconfig.
ICINGA2\_RLIMIT\_STACK |**Read-write.** Defines the resource limit for `RLIMIT_STACK` that should be set at start-up. Value cannot be set lower than the default `256 * 1024`. 0 disables the setting. Set in Icinga 2 sysconfig.
+#### Debug Constants and Variables
+
+These constants are only available in debug builds for developers and help with tracing messages and attaching to debuggers.
+
+Variable | Description
+---------------------------|-------------------
+Internal.DebugJsonRpc | **Read-write.** Setting this to `1` prints the raw JSON-RPC message to STDOUT.
+Internal.DebugWorkerDelay | **Read-write.** Delays the main worker process by X seconds after forked from the umbrella process. This helps with attaching LLDB which cannot follow child forks like GDB.
+
+Example:
+
+```
+$ icinga2 daemon -DInternal.DebugWorkerDelay=120
+Closed FD 6 which we inherited from our parent process.
+[2020-01-29 12:22:33 +0100] information/cli: Icinga application loader (version: v2.11.0-477-gfe8701d77; debug)
+[2020-01-29 12:22:33 +0100] information/RunWorker: DEBUG: Current PID: 85253. Sleeping for 120 seconds to allow lldb/gdb -p attachment.
+
+$ lldb -p 85253
+(lldb) b icinga::Checkable::ProcessCheckResult
+(lldb) c
+```
+
## Apply
diff --git a/lib/cli/daemoncommand.cpp b/lib/cli/daemoncommand.cpp
index ca7694f9f..090bb0257 100644
--- a/lib/cli/daemoncommand.cpp
+++ b/lib/cli/daemoncommand.cpp
@@ -191,6 +191,24 @@ pid_t l_UmbrellaPid = 0;
static Atomic l_AllowedToWork (false);
#endif /* _WIN32 */
+#ifdef I2_DEBUG
+/**
+ * Determine whether the developer wants to delay the worker process to attach a debugger to it.
+ *
+ * @return Internal.DebugWorkerDelay double
+ */
+static double GetDebugWorkerDelay()
+{
+ Namespace::Ptr internal = ScriptGlobal::Get("Internal", &Empty);
+
+ Value vdebug;
+ if (internal && internal->Get("DebugWorkerDelay", &vdebug))
+ return Convert::ToDouble(vdebug);
+
+ return 0.0;
+}
+#endif /* I2_DEBUG */
+
/**
* Do the actual work (config loading, ...)
*
@@ -203,6 +221,18 @@ static Atomic l_AllowedToWork (false);
static inline
int RunWorker(const std::vector& configs, bool closeConsoleLog = false, const String& stderrFile = String())
{
+
+#ifdef I2_DEBUG
+ double delay = GetDebugWorkerDelay();
+
+ if (delay > 0.0) {
+ Log(LogInformation, "RunWorker")
+ << "DEBUG: Current PID: " << Utility::GetPid() << ". Sleeping for " << delay << " seconds to allow lldb/gdb -p attachment.";
+
+ Utility::Sleep(delay);
+ }
+#endif /* I2_DEBUG */
+
Log(LogInformation, "cli", "Loading configuration file(s).");
{