diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp
index 01b48a4af92b4..be87ba68493f0 100644
--- a/Marlin/src/gcode/gcode.cpp
+++ b/Marlin/src/gcode/gcode.cpp
@@ -659,8 +659,15 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) {
case 82: M82(); break; // M82: Set E axis normal mode (same as other axes)
case 83: M83(); break; // M83: Set E axis relative mode
#endif
+
case 18: case 84: M18_M84(); break; // M18/M84: Disable Steppers / Set Timeout
case 85: M85(); break; // M85: Set inactivity stepper shutdown timeout
+
+ #if ENABLED(HOTEND_IDLE_TIMEOUT)
+ case 86: M86(); break; // M86: Set Hotend Idle Timeout
+ case 87: M87(); break; // M87: Cancel Hotend Idle Timeout
+ #endif
+
case 92: M92(); break; // M92: Set the steps-per-unit for one or more axes
case 114: M114(); break; // M114: Report current position
case 115: M115(); break; // M115: Report capabilities
diff --git a/Marlin/src/gcode/gcode.h b/Marlin/src/gcode/gcode.h
index 73729491adab2..17c84c8dd6a34 100644
--- a/Marlin/src/gcode/gcode.h
+++ b/Marlin/src/gcode/gcode.h
@@ -711,6 +711,13 @@ class GcodeSuite {
#endif
static void M85();
+
+ #if ENABLED(HOTEND_IDLE_TIMEOUT)
+ static void M86();
+ static void M86_report(const bool forReplay=true);
+ static void M87();
+ #endif
+
static void M92();
static void M92_report(const bool forReplay=true, const int8_t e=-1);
diff --git a/Marlin/src/gcode/temp/M86-M87.cpp b/Marlin/src/gcode/temp/M86-M87.cpp
new file mode 100644
index 0000000000000..7fb4461961235
--- /dev/null
+++ b/Marlin/src/gcode/temp/M86-M87.cpp
@@ -0,0 +1,79 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * 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, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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, see .
+ *
+ */
+
+/**
+ * gcode/temp/M86-M87.cpp
+ *
+ * Hotend Idle Timeout
+ */
+
+#include "../../inc/MarlinConfigPre.h"
+
+#if ENABLED(HOTEND_IDLE_TIMEOUT)
+
+#include "../gcode.h"
+#include "../../feature/hotend_idle.h"
+
+void GcodeSuite::M86_report(const bool forReplay/*=true*/) {
+ hotend_idle_settings_t &c = hotend_idle.cfg;
+ report_heading(forReplay, F("Hotend Idle Timeout"));
+ SERIAL_ECHOLNPGM(" M86"
+ #if HAS_HEATED_BED
+ " B", c.bed_target,
+ #endif
+ " E", c.nozzle_target,
+ " S", c.timeout,
+ " T", c.trigger
+ );
+}
+
+/**
+ * M86: Set / Report Hotend Idle Timeout
+ *
+ * Parameters
+ * S : Idle timeout. Set to 0 to disable.
+ * E : Extruder idle temperature to set on timeout
+ * B : Bed idle temperature to set on timeout
+ * T : Minimum extruder temperature to consider for timeout (> idle temperature)
+ */
+void GcodeSuite::M86() {
+ if (!parser.seen_any()) return M86_report();
+ hotend_idle_settings_t &c = hotend_idle.cfg;
+ if (parser.seenval('S')) c.timeout = parser.value_ushort();
+ if (parser.seenval('T')) c.trigger = parser.value_celsius();
+ if (parser.seenval('E')) c.nozzle_target = parser.value_celsius();
+ #if HAS_HEATED_BED
+ if (parser.seenval('B')) c.bed_target = parser.value_celsius();
+ #endif
+ const celsius_t min_trigger = c.nozzle_target + TEMP_HYSTERESIS;
+ if (c.trigger <= min_trigger)
+ SERIAL_ECHOLNPGM("?Idle Timeout (T) trigger temperature should be over ", min_trigger, "C.");
+}
+
+/**
+ * M86: Cancel Hotend Idle Timeout (by setting the timeout period to 0)
+ */
+void GcodeSuite::M87() {
+ hotend_idle.cfg.timeout = 0;
+}
+
+#endif // HOTEND_IDLE_TIMEOUT
diff --git a/Marlin/src/module/settings.cpp b/Marlin/src/module/settings.cpp
index d0757c3c84a3f..6bd2a8f1e523c 100644
--- a/Marlin/src/module/settings.cpp
+++ b/Marlin/src/module/settings.cpp
@@ -631,7 +631,7 @@ typedef struct SettingsDataStruct {
// HOTEND_IDLE_TIMEOUT
//
#if ENABLED(HOTEND_IDLE_TIMEOUT)
- hotend_idle_settings_t hotend_idle_config;
+ hotend_idle_settings_t hotend_idle_config; // M86 S T E B
#endif
} SettingsData;
@@ -3877,6 +3877,11 @@ void MarlinSettings::reset() {
//
TERN_(HAS_ZV_SHAPING, gcode.M593_report(forReplay));
+ //
+ // Hotend Idle Timeout
+ //
+ TERN_(HOTEND_IDLE_TIMEOUT, gcode.M86_report(forReplay));
+
//
// Linear Advance
//
diff --git a/ini/features.ini b/ini/features.ini
index 86e7d2e396bd9..63da77cf76c5e 100644
--- a/ini/features.ini
+++ b/ini/features.ini
@@ -140,7 +140,7 @@ HAS_FANMUX = build_src_filter=+ +
FWRETRACT = build_src_filter=+ +
HOST_ACTION_COMMANDS = build_src_filter=+
-HOTEND_IDLE_TIMEOUT = build_src_filter=+
+HOTEND_IDLE_TIMEOUT = build_src_filter=+ +
JOYSTICK = build_src_filter=+
BLINKM = build_src_filter=+
HAS_COLOR_LEDS = build_src_filter=+ +