diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h
index 3ad7dfdab33..3b6155f969d 100644
--- a/Marlin/Configuration.h
+++ b/Marlin/Configuration.h
@@ -1642,6 +1642,37 @@
  */
 //#define PRINTCOUNTER
 
+/**
+ * Password
+ *
+ * Set a numerical password for the printer which can be requested:
+ *
+ *  - When the printer boots up
+ *  - Upon opening the 'Print from Media' Menu
+ *  - When SD printing is completed or aborted
+ *
+ * The following G-codes can be used:
+ *
+ *  M510 - Lock Printer. Blocks all commands except M511.
+ *  M511 - Unlock Printer.
+ *  M512 - Set, Change and Remove Password.
+ *
+ * If you forget the password and get locked out you'll need to re-flash
+ * the firmware with the feature disabled, reset EEPROM, and (optionally)
+ * re-flash the firmware again with this feature enabled.
+ */
+//#define PASSWORD_FEATURE
+#if ENABLED(PASSWORD_FEATURE)
+  #define PASSWORD_LENGTH 4                 // (#) Number of digits (1-9). 3 or 4 is recommended
+  #define PASSWORD_ON_STARTUP
+  #define PASSWORD_UNLOCK_GCODE             // Unlock with the M511 P<password> command. Disable to prevent brute-force attack.
+  #define PASSWORD_CHANGE_GCODE             // Change the password with M512 P<old> N<new>.
+  //#define PASSWORD_ON_SD_PRINT_MENU       // This does not prevent gcodes from running
+  //#define PASSWORD_AFTER_SD_PRINT_END
+  //#define PASSWORD_AFTER_SD_PRINT_ABORT
+  //#include "Configuration_Secure.h"       // External file with PASSWORD_DEFAULT_VALUE
+#endif
+
 //=============================================================================
 //============================= LCD and SD support ============================
 //=============================================================================
diff --git a/Marlin/src/MarlinCore.cpp b/Marlin/src/MarlinCore.cpp
index a8c4407be29..39530395eb4 100644
--- a/Marlin/src/MarlinCore.cpp
+++ b/Marlin/src/MarlinCore.cpp
@@ -213,6 +213,10 @@
   #include "libs/L64XX/L64XX_Marlin.h"
 #endif
 
+#if ENABLED(PASSWORD_FEATURE)
+  #include "feature/password/password.h"
+#endif
+
 PGMSTR(NUL_STR, "");
 PGMSTR(M112_KILL_STR, "M112 Shutdown");
 PGMSTR(G28_STR, "G28");
@@ -452,11 +456,15 @@ void startOrResumeJob() {
     #ifdef EVENT_GCODE_SD_STOP
       queue.inject_P(PSTR(EVENT_GCODE_SD_STOP));
     #endif
+
+    TERN_(PASSWORD_AFTER_SD_PRINT_ABORT, password.lock_machine());
   }
 
   inline void finishSDPrinting() {
-    if (queue.enqueue_one_P(PSTR("M1001")))
+    if (queue.enqueue_one_P(PSTR("M1001"))) {
       marlin_state = MF_RUNNING;
+      TERN_(PASSWORD_AFTER_SD_PRINT_END, password.lock_machine());
+    }
   }
 
 #endif // SDSUPPORT
@@ -1205,6 +1213,10 @@ void setup() {
     SETUP_RUN(tft_lvgl_init());
   #endif
 
+  #if ENABLED(PASSWORD_ON_STARTUP)
+    SETUP_RUN(password.lock_machine());      // Will not proceed until correct password provided
+  #endif
+
   marlin_state = MF_RUNNING;
 
   SETUP_LOG("setup() completed.");
diff --git a/Marlin/src/core/language.h b/Marlin/src/core/language.h
index 5208b3e1bfb..48431455f0f 100644
--- a/Marlin/src/core/language.h
+++ b/Marlin/src/core/language.h
@@ -266,6 +266,13 @@
 #define STR_DEBUG_COMMUNICATION             "COMMUNICATION"
 #define STR_DEBUG_LEVELING                  "LEVELING"
 
+#define STR_PRINTER_LOCKED                  "Printer locked! (Unlock with M511 or LCD)"
+#define STR_WRONG_PASSWORD                  "Incorrect Password"
+#define STR_PASSWORD_TOO_LONG               "Password too long"
+#define STR_PASSWORD_REMOVED                "Password removed"
+#define STR_REMINDER_SAVE_SETTINGS          "Remember to save!"
+#define STR_PASSWORD_SET                    "Password is "
+
 // LCD Menu Messages
 
 #define LANGUAGE_DATA_INCL_(M) STRINGIFY_(fontdata/langdata_##M.h)
diff --git a/Marlin/src/core/macros.h b/Marlin/src/core/macros.h
index 3bd273872aa..5fc1081019b 100644
--- a/Marlin/src/core/macros.h
+++ b/Marlin/src/core/macros.h
@@ -342,15 +342,22 @@
 #endif
 
 // Macros for adding
-#define INC_0 1
-#define INC_1 2
-#define INC_2 3
-#define INC_3 4
-#define INC_4 5
-#define INC_5 6
-#define INC_6 7
-#define INC_7 8
-#define INC_8 9
+#define INC_0   1
+#define INC_1   2
+#define INC_2   3
+#define INC_3   4
+#define INC_4   5
+#define INC_5   6
+#define INC_6   7
+#define INC_7   8
+#define INC_8   9
+#define INC_9  10
+#define INC_10 11
+#define INC_11 12
+#define INC_12 13
+#define INC_13 14
+#define INC_14 15
+#define INC_15 16
 #define INCREMENT_(n) INC_##n
 #define INCREMENT(n) INCREMENT_(n)
 
@@ -367,16 +374,22 @@
 #define ADD10(N) ADD5(ADD5(N))
 
 // Macros for subtracting
-#define DEC_0 0
-#define DEC_1 0
-#define DEC_2 1
-#define DEC_3 2
-#define DEC_4 3
-#define DEC_5 4
-#define DEC_6 5
-#define DEC_7 6
-#define DEC_8 7
-#define DEC_9 8
+#define DEC_0   0
+#define DEC_1   0
+#define DEC_2   1
+#define DEC_3   2
+#define DEC_4   3
+#define DEC_5   4
+#define DEC_6   5
+#define DEC_7   6
+#define DEC_8   7
+#define DEC_9   8
+#define DEC_10  9
+#define DEC_11 10
+#define DEC_12 11
+#define DEC_13 12
+#define DEC_14 13
+#define DEC_15 14
 #define DECREMENT_(n) DEC_##n
 #define DECREMENT(n) DECREMENT_(n)
 
diff --git a/Marlin/src/feature/password/password.cpp b/Marlin/src/feature/password/password.cpp
new file mode 100644
index 00000000000..c519ee7c9c4
--- /dev/null
+++ b/Marlin/src/feature/password/password.cpp
@@ -0,0 +1,58 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "../../inc/MarlinConfigPre.h"
+
+#if ENABLED(PASSWORD_FEATURE)
+
+#include "password.h"
+#include "../../gcode/gcode.h"
+#include "../../core/serial.h"
+
+Password password;
+
+// public:
+bool     Password::is_set, Password::is_locked;
+uint32_t Password::value, Password::value_entry;
+
+//
+// Authenticate user with password.
+// Called from Setup, after SD Prinitng Stops/Aborts, and M510
+//
+void Password::lock_machine() {
+  is_locked = true;
+  TERN_(HAS_LCD_MENU, authenticate_user(ui.status_screen, screen_password_entry));
+}
+
+//
+// Authentication check
+//
+void Password::authentication_check() {
+  if (value_entry == value)
+    is_locked = false;
+  else
+    SERIAL_ECHOLNPGM(STR_WRONG_PASSWORD);
+
+  TERN_(HAS_LCD_MENU, authentication_done());
+}
+
+#endif // PASSWORD_FEATURE
diff --git a/Marlin/src/feature/password/password.h b/Marlin/src/feature/password/password.h
new file mode 100644
index 00000000000..66f1c70ba31
--- /dev/null
+++ b/Marlin/src/feature/password/password.h
@@ -0,0 +1,57 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include "../../lcd/ultralcd.h"
+
+class Password {
+public:
+  static bool is_set, is_locked;
+  static uint32_t value, value_entry;
+
+  Password() { is_locked = false; }
+
+  static void lock_machine();
+
+  #if HAS_LCD_MENU
+    static void access_menu_password();
+    static void authentication_check();
+    static void authentication_done();
+    static void media_gatekeeper();
+
+    private:
+    static void authenticate_user(const screenFunc_t, const screenFunc_t);
+    static void menu_password();
+    static void menu_password_entry();
+    static void screen_password_entry();
+    static void screen_set_password();
+    static void start_over();
+
+    static void digit_entered();
+    static void set_password_done();
+    static void menu_password_report();
+
+    static void remove_password();
+  #endif
+};
+
+extern Password password;
diff --git a/Marlin/src/gcode/feature/password/M510-M512.cpp b/Marlin/src/gcode/feature/password/M510-M512.cpp
new file mode 100644
index 00000000000..bcdeb7b91cc
--- /dev/null
+++ b/Marlin/src/gcode/feature/password/M510-M512.cpp
@@ -0,0 +1,83 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "../../../inc/MarlinConfigPre.h"
+
+#if ENABLED(PASSWORD_FEATURE)
+
+#include "../../../feature/password/password.h"
+#include "../../../core/serial.h"
+#include "../../gcode.h"
+
+//
+// M510: Lock Printer
+//
+void GcodeSuite::M510() {
+  password.lock_machine();
+}
+
+//
+// M511: Unlock Printer
+//
+#if ENABLED(PASSWORD_UNLOCK_GCODE)
+
+  void GcodeSuite::M511() {
+    if (password.is_locked) {
+      password.value_entry = parser.ulongval('P');
+      password.authentication_check();
+    }
+  }
+
+#endif // PASSWORD_UNLOCK_GCODE
+
+//
+// M512: Set/Change/Remove Password
+//
+#if ENABLED(PASSWORD_CHANGE_GCODE)
+
+  void GcodeSuite::M512() {
+    if (password.is_set && parser.ulongval('P') != password.value) {
+      SERIAL_ECHOLNPGM(STR_WRONG_PASSWORD);
+      return;
+     }
+
+    if (parser.seenval('N')) {
+      password.value_entry = parser.ulongval('N');
+
+      if (password.value_entry < CAT(1e, PASSWORD_LENGTH)) {
+        password.is_set = true;
+        password.value = password.value_entry;
+        SERIAL_ECHOLNPAIR(STR_PASSWORD_SET, password.value); // TODO: Update password.string
+      }
+      else
+        SERIAL_ECHOLNPGM(STR_PASSWORD_TOO_LONG);
+    }
+    else {
+      password.is_set = false;
+      SERIAL_ECHOLNPGM(STR_PASSWORD_REMOVED);
+    }
+    SERIAL_ECHOLNPGM(STR_REMINDER_SAVE_SETTINGS);
+  }
+
+#endif // PASSWORD_CHANGE_GCODE
+
+#endif // PASSWORD_FEATURE
diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp
index 2309953f881..840df54f6a7 100644
--- a/Marlin/src/gcode/gcode.cpp
+++ b/Marlin/src/gcode/gcode.cpp
@@ -57,6 +57,10 @@ GcodeSuite gcode;
   #include "../feature/spindle_laser.h"
 #endif
 
+#if ENABLED(PASSWORD_FEATURE)
+  #include "../feature/password/password.h"
+#endif
+
 #include "../MarlinCore.h" // for idle()
 
 // Inactivity shutdown
@@ -241,6 +245,17 @@ void GcodeSuite::dwell(millis_t time) {
 void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) {
   KEEPALIVE_STATE(IN_HANDLER);
 
+ /**
+  * Block all Gcodes except M511 Unlock Printer, if printer is locked
+  * Will still block Gcodes if M511 is disabled, in which case the printer should be unlocked via LCD Menu
+  */
+  #if ENABLED(PASSWORD_FEATURE)
+    if (password.is_locked && !(parser.command_letter == 'M' && parser.codenum == 511)) {
+      SERIAL_ECHO_MSG(STR_PRINTER_LOCKED);
+      return;
+    }
+  #endif
+
   // Handle a known G, M, or T
   switch (parser.command_letter) {
     case 'G': switch (parser.codenum) {
@@ -736,6 +751,16 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) {
         case 504: M504(); break;                                  // M504: Validate EEPROM contents
       #endif
 
+      #if ENABLED(PASSWORD_FEATURE)
+        case 510: M510(); break;                                  // M510: Lock Printer
+        #if ENABLED(PASSWORD_UNLOCK_GCODE)
+          case 511: M511(); break;                                // M511: Unlock Printer
+        #endif
+        #if ENABLED(PASSWORD_CHANGE_GCODE)
+          case 512: M512(); break;
+        #endif                                                    // M512: Set/Change/Remove Password
+      #endif
+
       #if ENABLED(SDSUPPORT)
         case 524: M524(); break;                                  // M524: Abort the current SD print job
       #endif
diff --git a/Marlin/src/gcode/gcode.h b/Marlin/src/gcode/gcode.h
index 783781b9c30..e04cd637eb9 100644
--- a/Marlin/src/gcode/gcode.h
+++ b/Marlin/src/gcode/gcode.h
@@ -225,6 +225,9 @@
  * M502 - Revert to the default "factory settings". ** Does not write them to EEPROM! **
  * M503 - Print the current settings (in memory): "M503 S<verbose>". S0 specifies compact output.
  * M504 - Validate EEPROM contents. (Requires EEPROM_SETTINGS)
+ * M510 - Lock Printer
+ * M511 - Unlock Printer
+ * M512 - Set/Change/Remove Password
  * M524 - Abort the current SD print job started with M24. (Requires SDSUPPORT)
  * M540 - Enable/disable SD card abort on endstop hit: "M540 S<state>". (Requires SD_ABORT_ON_ENDSTOP_HIT)
  * M569 - Enable stealthChop on an axis. (Requires at least one _DRIVER_TYPE to be TMC2130/2160/2208/2209/5130/5160)
@@ -760,6 +763,16 @@ private:
   #endif
   TERN_(EEPROM_SETTINGS, static void M504());
 
+  #if ENABLED(PASSWORD_FEATURE)
+    static void M510();
+    #if ENABLED(PASSWORD_UNLOCK_GCODE)
+      static void M511();
+    #endif
+    #if ENABLED(PASSWORD_CHANGE_GCODE)
+      static void M512();
+    #endif
+  #endif
+
   TERN_(SDSUPPORT, static void M524());
 
   TERN_(SD_ABORT_ON_ENDSTOP_HIT, static void M540());
diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h
index 7fbfda4fe10..f9b65c8bf48 100644
--- a/Marlin/src/inc/SanityCheck.h
+++ b/Marlin/src/inc/SanityCheck.h
@@ -3083,5 +3083,16 @@ static_assert(   _ARR_TEST(3,0) && _ARR_TEST(3,1) && _ARR_TEST(3,2)
   #error "ESP3D_WIFISUPPORT or WIFISUPPORT requires an ESP32 controller."
 #endif
 
+/**
+ * Sanity Check for Password Feature
+ */
+#if ENABLED(PASSWORD_FEATURE)
+  #if NONE(HAS_LCD_MENU, PASSWORD_UNLOCK_GCODE, PASSWORD_CHANGE_GCODE)
+    #error "Without PASSWORD_UNLOCK_GCODE, PASSWORD_CHANGE_GCODE, or a supported LCD there's no way to unlock the printer or set a password."
+  #elif DISABLED(EEPROM_SETTINGS)
+    #warning "PASSWORD_FEATURE settings will be lost on power-off without EEPROM_SETTINGS."
+  #endif
+#endif
+
 // Misc. Cleanup
 #undef _TEST_PWM
diff --git a/Marlin/src/lcd/language/language_en.h b/Marlin/src/lcd/language/language_en.h
index ca7ddd2b031..9f6178ae50c 100644
--- a/Marlin/src/lcd/language/language_en.h
+++ b/Marlin/src/lcd/language/language_en.h
@@ -588,6 +588,17 @@ namespace Language_en {
   PROGMEM Language_Str MSG_BAD_PAGE                        = _UxGT("Bad page index");
   PROGMEM Language_Str MSG_BAD_PAGE_SPEED                  = _UxGT("Bad page speed");
 
+  PROGMEM Language_Str MSG_EDIT_PASSWORD                   = _UxGT("Edit Password");
+  PROGMEM Language_Str MSG_LOGIN_REQUIRED                  = _UxGT("Login Required");
+  PROGMEM Language_Str MSG_PASSWORD_SETTINGS               = _UxGT("Password Settings");
+  PROGMEM Language_Str MSG_ENTER_DIGIT                     = _UxGT("Enter Digit");
+  PROGMEM Language_Str MSG_CHANGE_PASSWORD                 = _UxGT("Set/Edit Password");
+  PROGMEM Language_Str MSG_REMOVE_PASSWORD                 = _UxGT("Remove Password");
+  PROGMEM Language_Str MSG_PASSWORD_SET                    = _UxGT("Password is ");
+  PROGMEM Language_Str MSG_START_OVER                      = _UxGT("Start Over");
+  PROGMEM Language_Str MSG_REMINDER_SAVE_SETTINGS          = _UxGT("Remember to Save!");
+  PROGMEM Language_Str MSG_PASSWORD_REMOVED                = _UxGT("Password Removed");
+
   //
   // Filament Change screens show up to 3 lines on a 4-line display
   //                        ...or up to 2 lines on a 3-line display
diff --git a/Marlin/src/lcd/menu/menu_advanced.cpp b/Marlin/src/lcd/menu/menu_advanced.cpp
index 34def4d3bd7..e4178610722 100644
--- a/Marlin/src/lcd/menu/menu_advanced.cpp
+++ b/Marlin/src/lcd/menu/menu_advanced.cpp
@@ -51,6 +51,10 @@
   #include "../../module/settings.h"
 #endif
 
+#if ENABLED(PASSWORD_FEATURE)
+  #include "../../feature/password/password.h"
+#endif
+
 void menu_tmc();
 void menu_backlash();
 
@@ -603,6 +607,10 @@ void menu_advanced_settings() {
     });
   #endif
 
+  #if ENABLED(PASSWORD_FEATURE)
+    SUBMENU(MSG_PASSWORD_SETTINGS, password.access_menu_password);
+  #endif
+
   #if ENABLED(EEPROM_SETTINGS) && DISABLED(SLIM_LCD_MENUS)
     CONFIRM_ITEM(MSG_INIT_EEPROM,
       MSG_BUTTON_INIT, MSG_BUTTON_CANCEL,
diff --git a/Marlin/src/lcd/menu/menu_main.cpp b/Marlin/src/lcd/menu/menu_main.cpp
index 059290c5237..9a1d2ece68e 100644
--- a/Marlin/src/lcd/menu/menu_main.cpp
+++ b/Marlin/src/lcd/menu/menu_main.cpp
@@ -50,6 +50,10 @@
   #include "../../lcd/menu/menu_mmu2.h"
 #endif
 
+#if ENABLED(PASSWORD_FEATURE)
+  #include "../../feature/password/password.h"
+#endif
+
 void menu_tune();
 void menu_cancelobject();
 void menu_motion();
@@ -133,7 +137,7 @@ void menu_main() {
 
       if (card_detected) {
         if (!card_open) {
-          SUBMENU(MSG_MEDIA_MENU, menu_media);
+          SUBMENU(MSG_MEDIA_MENU, TERN(PASSWORD_ON_SD_PRINT_MENU, password.media_gatekeeper, menu_media));
           MENU_ITEM(gcode,
             #if PIN_EXISTS(SD_DETECT)
               MSG_CHANGE_MEDIA, M21_STR
@@ -240,7 +244,7 @@ void menu_main() {
               MSG_RELEASE_MEDIA, PSTR("M22")
             #endif
           );
-          SUBMENU(MSG_MEDIA_MENU, menu_media);
+          SUBMENU(MSG_MEDIA_MENU, TERN(PASSWORD_ON_SD_PRINT_MENU, password.media_gatekeeper, menu_media));
         }
       }
       else {
diff --git a/Marlin/src/lcd/menu/menu_password.cpp b/Marlin/src/lcd/menu/menu_password.cpp
new file mode 100644
index 00000000000..f8e0b567218
--- /dev/null
+++ b/Marlin/src/lcd/menu/menu_password.cpp
@@ -0,0 +1,184 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+//
+// Advanced Settings Menus
+//
+
+#include "../../inc/MarlinConfigPre.h"
+
+#if BOTH(HAS_LCD_MENU, PASSWORD_FEATURE)
+
+#include "../../feature/password/password.h"
+
+#include "menu.h"
+#include "menu_addon.h"
+
+void menu_advanced_settings();
+
+screenFunc_t success_screen, fail_screen;
+bool authenticating; // = false
+char string[(PASSWORD_LENGTH) + 1];
+static uint8_t digit_no;
+
+//
+// Screen for both editing and setting the password
+//
+void Password::menu_password_entry() {
+  START_MENU();
+
+  // "Login" or "New Code"
+  STATIC_ITEM_P(authenticating ? GET_TEXT(MSG_LOGIN_REQUIRED) : GET_TEXT(MSG_EDIT_PASSWORD), SS_CENTER|SS_INVERT);
+
+  STATIC_ITEM_P(PSTR(""), SS_CENTER|SS_INVERT, string);
+
+  // Make the digit edit item look like a sub-menu
+  PGM_P const label = GET_TEXT(MSG_ENTER_DIGIT);
+  EDIT_ITEM_P(uint8, label, &editable.uint8, 0, 9, digit_entered);
+  MENU_ITEM_ADDON_START(utf8_strlen_P(label) + 1);
+    lcd_put_wchar(' ');
+    lcd_put_wchar('1' + digit_no);
+    SETCURSOR_X(LCD_WIDTH - 1);
+    lcd_put_wchar('>');
+  MENU_ITEM_ADDON_END();
+
+  ACTION_ITEM(MSG_START_OVER, start_over);
+
+  if (!authenticating) BACK_ITEM(MSG_BUTTON_CANCEL);
+
+  END_MENU();
+}
+
+//
+// Authentication check
+//
+void Password::authentication_done() {
+  ui.goto_screen(is_locked ? fail_screen : success_screen);
+  ui.completion_feedback(!is_locked);
+}
+
+// A single digit was completed
+void Password::digit_entered() {
+  uint32_t multiplier = CAT(1e, PASSWORD_LENGTH); // 1e5 = 100000
+  LOOP_LE_N(i, digit_no) multiplier /= 10;
+  value_entry += editable.uint8 * multiplier;
+  string[digit_no++] = '0' + editable.uint8;
+
+  // Exit edit screen menu and go to another screen
+  ui.goto_previous_screen();
+  ui.use_click();
+  ui.goto_screen(menu_password_entry);
+
+  // After password has been keyed in
+  if (digit_no == PASSWORD_LENGTH) {
+    if (authenticating)
+      authentication_check();
+    else
+      set_password_done();
+  }
+}
+
+//
+// Set/Change Password
+//
+void Password::screen_password_entry() {
+  value_entry = 0;
+  digit_no = 0;
+  editable.uint8 = 0;
+  memset(string, '-', PASSWORD_LENGTH);
+  string[PASSWORD_LENGTH] = '\0';
+  menu_password_entry();
+}
+
+void Password::screen_set_password() {
+  authenticating = false;
+  screen_password_entry();
+}
+
+void Password::authenticate_user(const screenFunc_t in_succ_scr, const screenFunc_t in_fail_scr) {
+  success_screen = in_succ_scr;
+  fail_screen = in_fail_scr;
+  if (is_set) {
+    authenticating = true;
+    ui.goto_screen(screen_password_entry);
+    ui.defer_status_screen();
+    ui.update();
+  }
+  else {
+    ui.goto_screen(in_succ_scr);
+    is_locked = false;
+  }
+}
+
+void Password::access_menu_password() {
+  authenticate_user(menu_password, menu_advanced_settings);
+}
+
+#if ENABLED(PASSWORD_ON_SD_PRINT_MENU)
+  void Password::media_gatekeeper() {
+    authenticate_user(menu_media, menu_main);
+  }
+#endif
+
+void Password::start_over() {
+  ui.goto_previous_screen(); // Goto previous screen, if any
+  ui.goto_screen(screen_password_entry);
+}
+
+void Password::menu_password_report() {
+  START_SCREEN();
+  BACK_ITEM(MSG_PASSWORD_SETTINGS);
+  STATIC_ITEM(MSG_PASSWORD_SET, SS_LEFT, string);
+  STATIC_ITEM(MSG_REMINDER_SAVE_SETTINGS, SS_LEFT);
+  END_SCREEN();
+}
+
+void Password::set_password_done() {
+  is_set = true;
+  value = value_entry;
+  ui.completion_feedback(true);
+  ui.goto_screen(menu_password_report);
+}
+
+void Password::remove_password() {
+  is_set = false;
+  string[0] = '0';
+  string[1] = '\0';
+  ui.completion_feedback(true);
+  ui.goto_screen(menu_password_report);
+}
+
+//
+// Password Menu
+//
+void Password::menu_password() {
+  START_MENU();
+  BACK_ITEM(MSG_ADVANCED_SETTINGS);
+  SUBMENU(MSG_CHANGE_PASSWORD, screen_set_password);
+  ACTION_ITEM(MSG_REMOVE_PASSWORD, []{ ui.save_previous_screen(); remove_password(); } );
+  #if ENABLED(EEPROM_SETTINGS)
+    ACTION_ITEM(MSG_STORE_EEPROM, ui.store_settings);
+  #endif
+  END_MENU();
+}
+
+#endif // HAS_LCD_MENU && PASSWORD_FEATURE
diff --git a/Marlin/src/module/settings.cpp b/Marlin/src/module/settings.cpp
index 34af8f2ea39..f1ab0fca692 100644
--- a/Marlin/src/module/settings.cpp
+++ b/Marlin/src/module/settings.cpp
@@ -140,6 +140,10 @@
   #define HAS_CASE_LIGHT_BRIGHTNESS 1
 #endif
 
+#if ENABLED(PASSWORD_FEATURE)
+  #include "../feature/password/password.h"
+#endif
+
 #if ENABLED(TOUCH_SCREEN_CALIBRATION)
   #include "../lcd/tft/touch.h"
 #endif
@@ -152,7 +156,7 @@ typedef struct {  int16_t X, Y, Z, X2, Y2, Z2, Z3, Z4;
 typedef struct {     bool X, Y, Z, X2, Y2, Z2, Z3, Z4, E0, E1, E2, E3, E4, E5, E6, E7; } tmc_stealth_enabled_t;
 
 // Limit an index to an array size
-#define ALIM(I,ARR) _MIN(I, signed(COUNT(ARR) - 1))
+#define ALIM(I,ARR) _MIN(I, (signed)COUNT(ARR) - 1)
 
 // Defaults for reset / fill in on load
 static const uint32_t   _DMA[] PROGMEM = DEFAULT_MAX_ACCELERATION;
@@ -407,6 +411,14 @@ typedef struct SettingsDataStruct {
     uint8_t caselight_brightness;                        // M355 P
   #endif
 
+  //
+  // PASSWORD_FEATURE
+  //
+  #if ENABLED(PASSWORD_FEATURE)
+    bool password_is_set;
+    uint32_t password_value;
+  #endif
+
   //
   // TOUCH_SCREEN_CALIBRATION
   //
@@ -1345,6 +1357,14 @@ void MarlinSettings::postprocess() {
       EEPROM_WRITE(caselight.brightness);
     #endif
 
+    //
+    // Password feature
+    //
+    #if ENABLED(PASSWORD_FEATURE)
+      EEPROM_WRITE(password.is_set);
+      EEPROM_WRITE(password.value);
+    #endif
+
     //
     // TOUCH_SCREEN_CALIBRATION
     //
@@ -2185,6 +2205,15 @@ void MarlinSettings::postprocess() {
         EEPROM_READ(caselight.brightness);
       #endif
 
+      //
+      // Password feature
+      //
+      #if ENABLED(PASSWORD_FEATURE)
+        _FIELD_TEST(password_is_set);
+        EEPROM_READ(password.is_set);
+        EEPROM_READ(password.value);
+      #endif
+
       //
       // TOUCH_SCREEN_CALIBRATION
       //
@@ -2665,7 +2694,7 @@ void MarlinSettings::reset() {
       #define PID_DEFAULT(N,E) DEFAULT_##N
     #endif
     HOTEND_LOOP() {
-      PID_PARAM(Kp, e) = float(PID_DEFAULT(Kp, ALIM(e, defKp)));
+      PID_PARAM(Kp, e) =      float(PID_DEFAULT(Kp, ALIM(e, defKp)));
       PID_PARAM(Ki, e) = scalePID_i(PID_DEFAULT(Ki, ALIM(e, defKi)));
       PID_PARAM(Kd, e) = scalePID_d(PID_DEFAULT(Kd, ALIM(e, defKd)));
       TERN_(PID_EXTRUSION_SCALING, PID_PARAM(Kc, e) = float(PID_DEFAULT(Kc, ALIM(e, defKc))));
@@ -2783,6 +2812,15 @@ void MarlinSettings::reset() {
     }
   #endif
 
+  #if ENABLED(PASSWORD_FEATURE)
+    #ifdef PASSWORD_DEFAULT_VALUE
+      password.is_set = true;
+      password.value = PASSWORD_DEFAULT_VALUE;
+    #else
+      password.is_set = false;
+    #endif
+  #endif
+
   postprocess();
 
   DEBUG_ECHO_START();
diff --git a/buildroot/share/PlatformIO/scripts/common-dependencies.h b/buildroot/share/PlatformIO/scripts/common-dependencies.h
index d18cb8c2813..c41027003e9 100644
--- a/buildroot/share/PlatformIO/scripts/common-dependencies.h
+++ b/buildroot/share/PlatformIO/scripts/common-dependencies.h
@@ -143,6 +143,9 @@
   #if ENABLED(MMU2_MENUS)
     #define HAS_MENU_MMU2
   #endif
+  #if ENABLED(PASSWORD_FEATURE)
+    #define HAS_MENU_PASSWORD
+  #endif
   #if HAS_TRINAMIC_CONFIG
     #define HAS_MENU_TMC
   #endif
diff --git a/buildroot/tests/DUE-tests b/buildroot/tests/DUE-tests
index 5c36db03679..7f488f6126c 100755
--- a/buildroot/tests/DUE-tests
+++ b/buildroot/tests/DUE-tests
@@ -33,7 +33,7 @@ opt_set EXTRUDER_AUTO_FAN_SPEED 100
 opt_set TEMP_SENSOR_CHAMBER 3
 opt_add TEMP_CHAMBER_PIN 6
 opt_set HEATER_CHAMBER_PIN 45
-exec_test $1 $2 "RAMPS4DUE_EFB with ABL (Bilinear), EXTENSIBLE_UI, S-Curve, many options."
+exec_test $1 $2 "RAMPS4DUE_EFB with ABL (Bilinear), ExtUI, S-Curve, many options."
 
 restore_configs
 opt_set MOTHERBOARD BOARD_RADDS
diff --git a/buildroot/tests/rambo-tests b/buildroot/tests/rambo-tests
index 0b249e2149c..ec8af16c23b 100644
--- a/buildroot/tests/rambo-tests
+++ b/buildroot/tests/rambo-tests
@@ -33,6 +33,7 @@ opt_enable REPRAP_DISCOUNT_SMART_CONTROLLER LCD_PROGRESS_BAR LCD_PROGRESS_BAR_TE
            PRINTCOUNTER SERVICE_NAME_1 SERVICE_INTERVAL_1 LEVEL_BED_CORNERS \
            NOZZLE_PARK_FEATURE FILAMENT_RUNOUT_SENSOR FILAMENT_RUNOUT_DISTANCE_MM \
            ADVANCED_PAUSE_FEATURE FILAMENT_LOAD_UNLOAD_GCODES FILAMENT_UNLOAD_ALL_EXTRUDERS \
+           PASSWORD_FEATURE PASSWORD_ON_STARTUP PASSWORD_ON_SD_PRINT_MENU PASSWORD_AFTER_SD_PRINT_END PASSWORD_AFTER_SD_PRINT_ABORT \
            AUTO_BED_LEVELING_BILINEAR Z_MIN_PROBE_REPEATABILITY_TEST DISTINCT_E_FACTORS \
            SKEW_CORRECTION SKEW_CORRECTION_FOR_Z SKEW_CORRECTION_GCODE \
            BACKLASH_COMPENSATION BACKLASH_GCODE BAUD_RATE_GCODE BEZIER_CURVE_SUPPORT \
diff --git a/platformio.ini b/platformio.ini
index fdb120ae88b..10990b4d215 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -41,6 +41,7 @@ default_src_filter = +<src/*> -<src/config> -<src/HAL> +<src/HAL/shared>
   -<src/lcd/menu/menu_led.cpp>
   -<src/lcd/menu/menu_media.cpp>
   -<src/lcd/menu/menu_mmu2.cpp>
+  -<src/lcd/menu/menu_password.cpp>
   -<src/lcd/menu/menu_power_monitor.cpp>
   -<src/lcd/menu/menu_spindle_laser.cpp>
   -<src/lcd/menu/menu_temperature.cpp>
@@ -86,6 +87,7 @@ default_src_filter = +<src/*> -<src/config> -<src/HAL> +<src/HAL/shared>
   -<src/feature/max7219.cpp>
   -<src/feature/mixing.cpp>
   -<src/feature/mmu2> -<src/gcode/feature/prusa_MMU2>
+  -<src/feature/password> -<src/gcode/feature/password>
   -<src/feature/pause.cpp>
   -<src/feature/power.cpp>
   -<src/feature/power_monitor.cpp> -<src/gcode/feature/power_monitor>
@@ -231,6 +233,7 @@ HAS_MENU_LED            = src_filter=+<src/lcd/menu/menu_led.cpp>
 HAS_MENU_MEDIA          = src_filter=+<src/lcd/menu/menu_media.cpp>
 HAS_MENU_MIXER          = src_filter=+<src/lcd/menu/menu_mixer.cpp>
 HAS_MENU_MMU2           = src_filter=+<src/lcd/menu/menu_mmu2.cpp>
+HAS_MENU_PASSWORD       = src_filter=+<src/lcd/menu/menu_password.cpp>
 HAS_MENU_POWER_MONITOR  = src_filter=+<src/lcd/menu/menu_power_monitor.cpp>
 HAS_MENU_CUTTER         = src_filter=+<src/lcd/menu/menu_spindle_laser.cpp>
 HAS_MENU_TEMPERATURE    = src_filter=+<src/lcd/menu/menu_temperature.cpp>
@@ -276,6 +279,7 @@ TEMP_STAT_LEDS          = src_filter=+<src/feature/leds/tempstat.cpp>
 MAX7219_DEBUG           = src_filter=+<src/feature/max7219.cpp> +<src/gcode/feature/leds/M7219.cpp>
 MIXING_EXTRUDER         = src_filter=+<src/feature/mixing.cpp> +<src/gcode/feature/mixing/M163-M165.cpp>
 PRUSA_MMU2              = src_filter=+<src/feature/mmu2> +<src/gcode/feature/prusa_MMU2>
+PASSWORD_FEATURE        = src_filter=+<src/feature/password> +<src/gcode/feature/password>
 ADVANCED_PAUSE_FEATURE  = src_filter=+<src/feature/pause.cpp> +<src/gcode/feature/pause/M600.cpp> +<src/gcode/feature/pause/M603.cpp>
 AUTO_POWER_CONTROL      = src_filter=+<src/feature/power.cpp>
 HAS_POWER_MONITOR       = src_filter=+<src/feature/power_monitor.cpp> +<src/gcode/feature/power_monitor>