diff --git a/.travis.yml b/.travis.yml
index 5bfb6809bc..16bf750430 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -145,10 +145,10 @@ script:
   - opt_enable MESH_BED_LEVELING MESH_G28_REST_ORIGIN LCD_BED_LEVELING ULTIMAKERCONTROLLER
   - build_marlin
   #
-  # Test PROBE_MANUALLY feature
+  # Test PROBE_MANUALLY feature, with LCD support
   #
   - restore_configs
-  - opt_enable PROBE_MANUALLY AUTO_BED_LEVELING_BILINEAR
+  - opt_enable PROBE_MANUALLY AUTO_BED_LEVELING_BILINEAR LCD_BED_LEVELING ULTIMAKERCONTROLLER
   - build_marlin
   #
   # Test EEPROM_SETTINGS, EEPROM_CHITCHAT, M100_FREE_MEMORY_WATCHER,
diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp
index 7be9be703b..67e97dd786 100755
--- a/Marlin/Marlin_main.cpp
+++ b/Marlin/Marlin_main.cpp
@@ -3503,7 +3503,7 @@ inline void gcode_G4() {
 #endif // Z_SAFE_HOMING
 
 #if ENABLED(PROBE_MANUALLY)
-  static bool g29_in_progress = false;
+  bool g29_in_progress = false;
 #else
   constexpr bool g29_in_progress = false;
 #endif
diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp
index f8cdec5f5a..f407424427 100755
--- a/Marlin/ultralcd.cpp
+++ b/Marlin/ultralcd.cpp
@@ -457,13 +457,18 @@ uint16_t max_display_update_time = 0;
    * Synchronize safely while holding the current screen
    * This blocks all further screen or stripe updates once called
    */
+  extern uint8_t commands_in_queue;
+
   inline void lcd_synchronize() {
     lcd_implementation_drawmenu_static(LCD_HEIGHT >= 4 ? 1 : 0, PSTR(MSG_MOVING));
     if (no_reentrance) return;
     no_reentrance = true;
     screenFunc_t old_screen = currentScreen;
     lcd_goto_screen(lcd_synchronize);
-    stepper.synchronize();
+    while (commands_in_queue) {
+      idle();
+      stepper.synchronize();
+    }
     no_reentrance = false;
     lcd_goto_screen(old_screen);
   }
@@ -982,7 +987,7 @@ void kill_screen(const char* lcd_msg) {
     MENU_ITEM_EDIT(int3, MSG_SPEED, &feedrate_percentage, 10, 999);
 
     // Manual bed leveling, Bed Z:
-    #if ENABLED(LCD_BED_LEVELING)
+    #if ENABLED(MESH_BED_LEVELING) && ENABLED(LCD_BED_LEVELING)
       MENU_ITEM_EDIT(float43, MSG_BED_Z, &mbl.z_offset, -1, 1);
     #endif
 
@@ -1325,30 +1330,53 @@ void kill_screen(const char* lcd_msg) {
 
     /**
      *
-     * "Prepare" > "Bed Leveling" handlers
+     * "Prepare" > "Level Bed" handlers
      *
      */
 
     static uint8_t manual_probe_index;
 
-    // Utility to go to the next mesh point
-    inline void _manual_probe_xy(float x, float y) {
-      if (no_reentrance) return;
-      #if MANUAL_PROBE_HEIGHT > 0
-        current_position[Z_AXIS] = LOGICAL_Z_POSITION(Z_MIN_POS) + MANUAL_PROBE_HEIGHT;
-        line_to_current(Z_AXIS);
-      #endif
-      current_position[X_AXIS] = LOGICAL_X_POSITION(x);
-      current_position[Y_AXIS] = LOGICAL_Y_POSITION(y);
-      planner.buffer_line_kinematic(current_position, MMM_TO_MMS(XY_PROBE_SPEED), active_extruder);
-      #if MANUAL_PROBE_HEIGHT > 0
-        current_position[Z_AXIS] = LOGICAL_Z_POSITION(Z_MIN_POS) + 0.2;
-        line_to_current(Z_AXIS);
-      #endif
-      lcd_synchronize();
-    }
+    #if ENABLED(PROBE_MANUALLY)
+      extern bool g29_in_progress;
+    #endif
 
-    void _lcd_level_goto_next_point();
+    // LCD probed points are from defaults
+    constexpr uint8_t total_probe_points =
+      #if ABL_GRID
+        (ABL_GRID_MAX_POINTS_X) * (ABL_GRID_MAX_POINTS_Y)
+      #elif ENABLED(AUTO_BED_LEVELING_3POINT)
+        int(3)
+      #elif ENABLED(AUTO_BED_LEVELING_UBL)
+        (UBL_MESH_NUM_X_POINTS) * (UBL_MESH_NUM_Y_POINTS)
+      #elif ENABLED(MESH_BED_LEVELING)
+        (MESH_NUM_X_POINTS) * (MESH_NUM_Y_POINTS)
+      #endif
+    ;
+
+    #if ENABLED(MESH_BED_LEVELING)
+
+      // Utility to go to the next mesh point
+      inline void _manual_probe_goto_xy(float x, float y) {
+        if (no_reentrance) return;
+        #if MANUAL_PROBE_HEIGHT > 0
+          current_position[Z_AXIS] = LOGICAL_Z_POSITION(Z_MIN_POS) + MANUAL_PROBE_HEIGHT;
+          line_to_current(Z_AXIS);
+        #endif
+        current_position[X_AXIS] = LOGICAL_X_POSITION(x);
+        current_position[Y_AXIS] = LOGICAL_Y_POSITION(y);
+        planner.buffer_line_kinematic(current_position, MMM_TO_MMS(XY_PROBE_SPEED), active_extruder);
+        #if MANUAL_PROBE_HEIGHT > 0
+          current_position[Z_AXIS] = LOGICAL_Z_POSITION(Z_MIN_POS) + 0.2;
+          line_to_current(Z_AXIS);
+        #endif
+        lcd_synchronize();
+      }
+
+    #endif // MESH_BED_LEVELING
+
+    #if ENABLED(MESH_BED_LEVELING) || ENABLED(PROBE_MANUALLY)
+      void _lcd_level_goto_next_point();
+    #endif
 
     void _lcd_level_bed_done() {
       if (lcdDrawUpdate) lcd_implementation_drawedit(PSTR(MSG_LEVEL_BED_DONE));
@@ -1356,7 +1384,19 @@ void kill_screen(const char* lcd_msg) {
     }
 
     /**
-     * Step 7: Get the Z coordinate, then goto next point or exit
+     * Step 6: Display "Next point: 1 / 9" while waiting for move to finish
+     */
+    void _lcd_level_bed_moving() {
+      if (lcdDrawUpdate) {
+        char msg[10];
+        sprintf_P(msg, PSTR("%i / %u"), (int)(manual_probe_index + 1), total_probe_points);
+        lcd_implementation_drawedit(PSTR(MSG_LEVEL_BED_NEXT_POINT), msg);
+      }
+      lcdDrawUpdate = LCDVIEW_KEEP_REDRAWING;
+    }
+
+    /**
+     * Step 7: Get the Z coordinate, click goes to the next point or exits
      */
     void _lcd_level_bed_get_z() {
       ENCODER_DIRECTION_NORMAL();
@@ -1368,77 +1408,129 @@ void kill_screen(const char* lcd_msg) {
         refresh_cmd_timeout();
         current_position[Z_AXIS] += float((int32_t)encoderPosition) * (MBL_Z_STEP);
         NOLESS(current_position[Z_AXIS], -(LCD_PROBE_Z_RANGE) * 0.5);
-        NOMORE(current_position[Z_AXIS], (LCD_PROBE_Z_RANGE) * 0.5);
+        NOMORE(current_position[Z_AXIS],  (LCD_PROBE_Z_RANGE) * 0.5);
         line_to_current(Z_AXIS);
         lcdDrawUpdate = LCDVIEW_KEEP_REDRAWING;
         encoderPosition = 0;
       }
 
       if (lcd_clicked) {
-        mbl.set_zigzag_z(manual_probe_index++, current_position[Z_AXIS]);
-        if (manual_probe_index == (MESH_NUM_X_POINTS) * (MESH_NUM_Y_POINTS)) {
+
+        // Use a hook to set the probe point z
+        // (zigzag arranges in XY order)
+        #if ENABLED(AUTO_BED_LEVELING_UBL)
+
+          // UBL set-z handling goes here
+
+        #elif ENABLED(PROBE_MANUALLY)
+
+          // G29 helpfully records Z and goes to the next
+          // point (or beeps if done)
+          enqueue_and_echo_commands_P(PSTR("G29"));
+          manual_probe_index++;
+
+        #elif ENABLED(MESH_BED_LEVELING)
+
+          mbl.set_zigzag_z(manual_probe_index++, current_position[Z_AXIS]);
+
+        #endif
+
+        // If done...
+        if (manual_probe_index == total_probe_points) {
+
+          // Say "Done!"
           lcd_goto_screen(_lcd_level_bed_done);
 
+          // Raise Z to the "manual probe height"
           #if MANUAL_PROBE_HEIGHT > 0
             current_position[Z_AXIS] = LOGICAL_Z_POSITION(Z_MIN_POS) + MANUAL_PROBE_HEIGHT;
             line_to_current(Z_AXIS);
             lcd_synchronize();
           #endif
 
-          mbl.set_has_mesh(true);
-          mbl.set_reactivate(true);
-          enqueue_and_echo_commands_P(PSTR("G28"));
+          // Enable leveling, if needed
+          #if ENABLED(MESH_BED_LEVELING)
+
+            mbl.set_has_mesh(true);
+            mbl.set_reactivate(true);
+            enqueue_and_echo_commands_P(PSTR("G28"));
+
+          #elif ENABLED(AUTO_BED_LEVELING_UBL)
+
+            // UBL enable goes here
+
+          #elif ENABLED(PROBE_MANUALLY)
+
+            // ABL will be enabled due to "G29".
+
+          #endif
+
           lcd_return_to_status();
           //LCD_MESSAGEPGM(MSG_LEVEL_BED_DONE);
           lcd_completion_feedback();
         }
         else {
-          lcd_goto_screen(_lcd_level_goto_next_point);
+
+          // Move to the next probe point, if needed
+          #if ENABLED(MESH_BED_LEVELING) || ENABLED(PROBE_MANUALLY)
+
+            _lcd_level_goto_next_point();
+
+          #elif ENABLED(AUTO_BED_LEVELING_UBL)
+
+            // UBL goto-next-point goes here
+
+          #endif
         }
       }
 
-KeepDrawing:
+      KeepDrawing:
+
       // Update on first display, then only on updates to Z position
       // Show message above on clicks instead
       if (lcdDrawUpdate) {
         const float v = current_position[Z_AXIS];
         lcd_implementation_drawedit(PSTR(MSG_MOVE_Z), ftostr43sign(v + (v < 0 ? -0.0001 : 0.0001), '+'));
       }
-
     }
 
-    /**
-     * Step 6: Display "Next point: 1 / 9" while waiting for move to finish
-     */
-    void _lcd_level_bed_moving() {
-      if (lcdDrawUpdate) {
-        char msg[10];
+    #if ENABLED(MESH_BED_LEVELING) || ENABLED(PROBE_MANUALLY)
+
+      /**
+       * Step 5: Initiate a move to the next point
+       */
+      void _lcd_level_goto_next_point() {
+
+        // Set the menu to display ahead of blocking call
+        lcd_goto_screen(_lcd_level_bed_moving);
+
         #if ENABLED(MESH_BED_LEVELING)
-          sprintf_P(msg, PSTR("%i / %u"), (int)(manual_probe_index + 1), (MESH_NUM_X_POINTS) * (MESH_NUM_Y_POINTS));
+
+          int8_t px, py;
+          mbl.zigzag(manual_probe_index, px, py);
+
+          // Controls the loop until the move is done
+          _manual_probe_goto_xy(
+            LOGICAL_X_POSITION(mbl.index_to_xpos[px]),
+            LOGICAL_Y_POSITION(mbl.index_to_ypos[py])
+          );
+
         #elif ENABLED(AUTO_BED_LEVELING_UBL)
-          sprintf_P(msg, PSTR("%i / %u"), (int)(manual_probe_index + 1), (UBL_MESH_NUM_X_POINTS) * (UBL_MESH_NUM_Y_POINTS));
+
+          // UBL may have its own methodology
+
+        #elif ENABLED(PROBE_MANUALLY)
+
+          // Just wait for the G29 move to complete
+          lcd_synchronize();
+
         #endif
-        lcd_implementation_drawedit(PSTR(MSG_LEVEL_BED_NEXT_POINT), msg);
+
+        // After the blocking function returns, change menus
+        lcd_goto_screen(_lcd_level_bed_get_z);
       }
 
-      lcdDrawUpdate = LCDVIEW_KEEP_REDRAWING;
-    }
-
-    /**
-     * Step 5: Initiate a move to the next point
-     */
-    void _lcd_level_goto_next_point() {
-      // Set the menu to display ahead of blocking call
-      lcd_goto_screen(_lcd_level_bed_moving);
-
-      // _manual_probe_xy runs the menu loop until the move is done
-      int8_t px, py;
-      mbl.zigzag(manual_probe_index, px, py);
-      _manual_probe_xy(mbl.index_to_xpos[px], mbl.index_to_ypos[py]);
-
-      // After the blocking function returns, change menus
-      lcd_goto_screen(_lcd_level_bed_get_z);
-    }
+    #endif // MESH_BED_LEVELING
 
     /**
      * Step 4: Display "Click to Begin", wait for click
@@ -1448,7 +1540,14 @@ KeepDrawing:
       if (lcdDrawUpdate) lcd_implementation_drawedit(PSTR(MSG_LEVEL_BED_WAITING));
       if (lcd_clicked) {
         manual_probe_index = 0;
-        lcd_goto_screen(_lcd_level_goto_next_point);
+        #if ENABLED(MESH_BED_LEVELING)
+          _lcd_level_goto_next_point();
+        #elif ENABLED(AUTO_BED_LEVELING_UBL)
+          // UBL click handling should go here
+        #elif ENABLED(PROBE_MANUALLY)
+          enqueue_and_echo_commands_P(PSTR("G29"));
+          _lcd_level_goto_next_point();
+        #endif
       }
     }
 
@@ -1466,15 +1565,17 @@ KeepDrawing:
      * Step 2: Continue Bed Leveling...
      */
     void _lcd_level_bed_continue() {
+      #if PLANNER_LEVELING && DISABLED(AUTO_BED_LEVELING_UBL)
+        reset_bed_level();
+      #endif
       defer_return_to_status = true;
       axis_homed[X_AXIS] = axis_homed[Y_AXIS] = axis_homed[Z_AXIS] = false;
-      mbl.reset();
-      enqueue_and_echo_commands_P(PSTR("G28"));
       lcd_goto_screen(_lcd_level_bed_homing);
+      enqueue_and_echo_commands_P(PSTR("G28"));
     }
 
     /**
-     * Step 1: MBL entry-point: "Cancel" or "Level Bed"
+     * Step 1: Bed Level entry-point: "Cancel" or "Level Bed"
      */
     void lcd_level_bed() {
       START_MENU();
@@ -1483,7 +1584,7 @@ KeepDrawing:
       END_MENU();
     }
 
-  #endif  // LCD_BED_LEVELING
+  #endif // LCD_BED_LEVELING
 
   /**
    *
@@ -1520,12 +1621,19 @@ KeepDrawing:
     //
     // Level Bed
     //
-    #if HAS_ABL
+    #if ENABLED(LCD_BED_LEVELING)
+
+      #if ENABLED(PROBE_MANUALLY)
+        if (!g29_in_progress)
+      #endif
+          MENU_ITEM(submenu, MSG_LEVEL_BED, lcd_level_bed);
+
+    #elif HAS_ABL
+
       MENU_ITEM(gcode, MSG_LEVEL_BED,
         axis_homed[X_AXIS] && axis_homed[Y_AXIS] ? PSTR("G29") : PSTR("G28\nG29")
       );
-    #elif ENABLED(LCD_BED_LEVELING)
-      MENU_ITEM(submenu, MSG_LEVEL_BED, lcd_level_bed);
+
     #endif
 
     #if DISABLED(NO_WORKSPACE_OFFSETS)
@@ -2253,7 +2361,7 @@ KeepDrawing:
       MENU_ITEM_EDIT(float32, MSG_ZPROBE_ZOFFSET, &zprobe_zoffset, Z_PROBE_OFFSET_RANGE_MIN, Z_PROBE_OFFSET_RANGE_MAX);
     #endif
     // Manual bed leveling, Bed Z:
-    #if ENABLED(LCD_BED_LEVELING)
+    #if ENABLED(MESH_BED_LEVELING) && ENABLED(LCD_BED_LEVELING)
       MENU_ITEM_EDIT(float43, MSG_BED_Z, &mbl.z_offset, -1, 1);
     #endif
     MENU_ITEM_EDIT(float5, MSG_ACC, &planner.acceleration, 10, 99000);