diff --git a/.travis.yml b/.travis.yml
index 0f02842159b..ccdb5cfd950 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -62,7 +62,7 @@ script:
   - opt_enable PIDTEMPBED FIX_MOUNTED_PROBE Z_SAFE_HOMING ARC_P_CIRCLES CNC_WORKSPACE_PLANES CNC_COORDINATE_SYSTEMS
   - opt_enable REPRAP_DISCOUNT_SMART_CONTROLLER SDSUPPORT EEPROM_SETTINGS
   - opt_enable BLINKM PCA9632 RGB_LED NEOPIXEL_LED
-  - opt_enable AUTO_BED_LEVELING_LINEAR Z_MIN_PROBE_REPEATABILITY_TEST DEBUG_LEVELING_FEATURE
+  - opt_enable AUTO_BED_LEVELING_LINEAR Z_MIN_PROBE_REPEATABILITY_TEST DEBUG_LEVELING_FEATURE SKEW_CORRECTION SKEW_CORRECTION_FOR_Z SKEW_CORRECTION_GCODE
   - opt_enable_adv FWRETRACT MAX7219_DEBUG LED_CONTROL_MENU
   - opt_set ABL_GRID_POINTS_X 16
   - opt_set ABL_GRID_POINTS_Y 16
diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h
index 44649e9dd87..c1c5add624e 100644
--- a/Marlin/Configuration.h
+++ b/Marlin/Configuration.h
@@ -832,7 +832,7 @@
 //===========================================================================
 //=============================== Bed Leveling ==============================
 //===========================================================================
-// @section bedlevel
+// @section calibrate
 
 /**
  * Choose one of the options below to enable G29 Bed Leveling. The parameters
@@ -1039,6 +1039,63 @@
 #define HOMING_FEEDRATE_XY (50*60)
 #define HOMING_FEEDRATE_Z  (4*60)
 
+// @section calibrate
+
+/**
+ * Bed Skew Compensation
+ *
+ * This feature corrects for misalignment in the XYZ axes.
+ *
+ * Take the following steps to get the bed skew in the XY plane:
+ *  1. Print a test square (e.g., https://www.thingiverse.com/thing:2563185)
+ *  2. For XY_DIAG_AC measure the diagonal A to C
+ *  3. For XY_DIAG_BD measure the diagonal B to D
+ *  4. For XY_SIDE_AD measure the edge A to D
+ *
+ * Marlin automatically computes skew factors from these measurements.
+ * Skew factors may also be computed and set manually:
+ *
+ *  - Compute AB     : SQRT(2*AC*AC+2*BD*BD-4*AD*AD)/2
+ *  - XY_SKEW_FACTOR : TAN(PI/2-ACOS((AC*AC-AB*AB-AD*AD)/(2*AB*AD)))
+ *
+ * If desired, follow the same procedure for XZ and YZ.
+ * Use these diagrams for reference:
+ *
+ *    Y                     Z                     Z
+ *    ^     B-------C       ^     B-------C       ^     B-------C
+ *    |    /       /        |    /       /        |    /       /
+ *    |   /       /         |   /       /         |   /       /
+ *    |  A-------D          |  A-------D          |  A-------D
+ *    +-------------->X     +-------------->X     +-------------->Y
+ *     XY_SKEW_FACTOR        XZ_SKEW_FACTOR        YZ_SKEW_FACTOR
+ */
+//#define SKEW_CORRECTION
+
+#if ENABLED(SKEW_CORRECTION)
+  // Input all length measurements here:
+  #define XY_DIAG_AC 282.8427124746
+  #define XY_DIAG_BD 282.8427124746
+  #define XY_SIDE_AD 200
+
+  // Or, set the default skew factors directly here
+  // to override the above measurements:
+  #define XY_SKEW_FACTOR 0.0
+
+  //#define SKEW_CORRECTION_FOR_Z
+  #if ENABLED(SKEW_CORRECTION_FOR_Z)
+    #define XZ_DIAG_AC 282.8427124746
+    #define XZ_DIAG_BD 282.8427124746
+    #define YZ_DIAG_AC 282.8427124746
+    #define YZ_DIAG_BD 282.8427124746
+    #define YZ_SIDE_AD 200
+    #define XZ_SKEW_FACTOR 0.0
+    #define YZ_SKEW_FACTOR 0.0
+  #endif
+
+  // Enable this option for M852 to set skew at runtime
+  //#define SKEW_CORRECTION_GCODE
+#endif
+
 //=============================================================================
 //============================= Additional Features ===========================
 //=============================================================================
diff --git a/Marlin/src/core/language.h b/Marlin/src/core/language.h
index 354971ce234..e4ce07fe965 100644
--- a/Marlin/src/core/language.h
+++ b/Marlin/src/core/language.h
@@ -130,7 +130,6 @@
 #define MSG_ERR_LINE_NO                     "Line Number is not Last Line Number+1, Last Line: "
 #define MSG_ERR_CHECKSUM_MISMATCH           "checksum mismatch, Last Line: "
 #define MSG_ERR_NO_CHECKSUM                 "No Checksum with line number, Last Line: "
-#define MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM "No Line Number with checksum, Last Line: "
 #define MSG_FILE_PRINTED                    "Done printing file"
 #define MSG_BEGIN_FILE_LIST                 "Begin file list"
 #define MSG_END_FILE_LIST                   "End file list"
@@ -163,6 +162,9 @@
 #define MSG_Z2_MAX                          "z2_max: "
 #define MSG_Z_PROBE                         "z_probe: "
 #define MSG_PROBE_Z_OFFSET                  "Probe Z Offset"
+#define MSG_SKEW_MIN                        "min_skew_factor: "
+#define MSG_SKEW_MAX                        "max_skew_factor: "
+#define MSG_SKEW_WARN                       "WARNING: Skew compensation disabled (outside MIN/MAX limits)"
 #define MSG_FILAMENT_RUNOUT_SENSOR          "filament: "
 #define MSG_ERR_MATERIAL_INDEX              "M145 S<index> out of range (0-1)"
 #define MSG_ERR_M355_NONE                   "No case light"
diff --git a/Marlin/src/gcode/calibrate/M852.cpp b/Marlin/src/gcode/calibrate/M852.cpp
new file mode 100644
index 00000000000..66d950a2b67
--- /dev/null
+++ b/Marlin/src/gcode/calibrate/M852.cpp
@@ -0,0 +1,89 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (C) 2016 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/MarlinConfig.h"
+
+#if ENABLED(SKEW_CORRECTION_GCODE)
+
+#include "../gcode.h"
+#include "../../module/planner.h"
+
+/**
+ * M852: Get or set the machine skew factors. Reports current values with no arguments.
+ *
+ *  S[xy_factor] - Alias for 'I'
+ *  I[xy_factor] - New XY skew factor
+ *  J[xz_factor] - New XZ skew factor
+ *  K[yz_factor] - New YZ skew factor
+ */
+void GcodeSuite::M852() {
+  const bool ijk = parser.seen('I') || parser.seen('S')
+    #if ENABLED(SKEW_CORRECTION_FOR_Z)
+      || parser.seen('J') || parser.seen('K')
+    #endif
+  ;
+  bool badval = false;
+
+  if (parser.seen('I') || parser.seen('S')) {
+    const float value = parser.value_linear_units();
+    if (WITHIN(value, SKEW_FACTOR_MIN, SKEW_FACTOR_MAX))
+      planner.xy_skew_factor = value;
+    else
+      badval = true;
+  }
+
+  #if ENABLED(SKEW_CORRECTION_FOR_Z)
+
+    if (parser.seen('J')) {
+      const float value = parser.value_linear_units();
+      if (WITHIN(value, SKEW_FACTOR_MIN, SKEW_FACTOR_MAX))
+        planner.xz_skew_factor = value;
+      else
+        badval = true;
+    }
+
+    if (parser.seen('K')) {
+      const float value = parser.value_linear_units();
+      if (WITHIN(value, SKEW_FACTOR_MIN, SKEW_FACTOR_MAX))
+        planner.yz_skew_factor = value;
+      else
+        badval = true;
+    }
+
+  #endif
+
+  if (badval)
+    SERIAL_ECHOLNPGM(MSG_SKEW_MIN " " STRINGIFY(SKEW_FACTOR_MIN) " " MSG_SKEW_MAX " " STRINGIFY(SKEW_FACTOR_MAX));
+
+  if (!ijk) {
+    SERIAL_ECHO_START();
+    SERIAL_ECHOPAIR(MSG_SKEW_FACTOR " XY: ", planner.xy_skew_factor);
+    #if ENABLED(SKEW_CORRECTION_FOR_Z)
+      SERIAL_ECHOPAIR(" XZ: ", planner.xz_skew_factor);
+      SERIAL_ECHOLNPAIR(" YZ: ", planner.yz_skew_factor);
+    #else
+      SERIAL_EOL();
+    #endif
+  }
+}
+
+#endif // SKEW_CORRECTION_GCODE
diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp
index fdb73256b05..cce5d2d57ab 100644
--- a/Marlin/src/gcode/gcode.cpp
+++ b/Marlin/src/gcode/gcode.cpp
@@ -622,6 +622,12 @@ void GcodeSuite::process_parsed_command() {
           break;
       #endif // HAS_BED_PROBE
 
+      #if ENABLED(SKEW_CORRECTION_GCODE)
+        case 852: // M852: Set Skew factors
+          M852();
+          break;
+      #endif
+
       #if ENABLED(ADVANCED_PAUSE_FEATURE)
         case 600: // M600: Pause for filament change
           M600();
diff --git a/Marlin/src/gcode/gcode.h b/Marlin/src/gcode/gcode.h
index 7f89004ac23..2b2a1c24c3d 100644
--- a/Marlin/src/gcode/gcode.h
+++ b/Marlin/src/gcode/gcode.h
@@ -201,6 +201,7 @@
  * M666 - Set delta endstop adjustment. (Requires DELTA)
  * M605 - Set dual x-carriage movement mode: "M605 S<mode> [X<x_offset>] [R<temp_offset>]". (Requires DUAL_X_CARRIAGE)
  * M851 - Set Z probe's Z offset in current units. (Negative = below the nozzle.)
+ * M852 - Set skew factors: "M852 [I<xy>] [J<xz>] [K<yz>]". (Requires SKEW_CORRECTION_GCODE, and SKEW_CORRECTION_FOR_Z for IJ)
  * M860 - Report the position of position encoder modules.
  * M861 - Report the status of position encoder modules.
  * M862 - Perform an axis continuity test for position encoder modules.
@@ -705,6 +706,10 @@ private:
     static void M851();
   #endif
 
+  #if ENABLED(SKEW_CORRECTION_GCODE)
+    static void M852();
+  #endif
+
   #if ENABLED(I2C_POSITION_ENCODERS)
     FORCE_INLINE static void M860() { I2CPEM.M860(); }
     FORCE_INLINE static void M861() { I2CPEM.M861(); }
diff --git a/Marlin/src/inc/Conditionals_post.h b/Marlin/src/inc/Conditionals_post.h
index cf128a989f1..569b58551a8 100644
--- a/Marlin/src/inc/Conditionals_post.h
+++ b/Marlin/src/inc/Conditionals_post.h
@@ -888,6 +888,49 @@
   #define Z_PROBE_OFFSET_FROM_EXTRUDER 0
 #endif
 
+/**
+ * XYZ Bed Skew Correction
+ */
+#if ENABLED(SKEW_CORRECTION)
+  #define SKEW_FACTOR_MIN -1
+  #define SKEW_FACTOR_MAX 1
+
+  #define _GET_SIDE(a,b,c) (SQRT(2*sq(a)+2*sq(b)-4*sq(c))*0.5)
+  #define _SKEW_SIDE(a,b,c) tan(M_PI*0.5-acos((sq(a)-sq(b)-sq(c))/(2*c*b)))
+  #define _SKEW_FACTOR(a,b,c) _SKEW_SIDE(a,_GET_SIDE(a,b,c),c)
+
+  #ifndef XY_SKEW_FACTOR
+    constexpr float XY_SKEW_FACTOR = (
+      #if defined(XY_DIAG_AC) && defined(XY_DIAG_BD) && defined(XY_SIDE_AD)
+        _SKEW_FACTOR(XY_DIAG_AC, XY_DIAG_BD, XY_SIDE_AD)
+      #else
+        0.0
+      #endif
+    );
+  #endif
+  #ifndef XZ_SKEW_FACTOR
+    #if defined(XY_SIDE_AD) && !defined(XZ_SIDE_AD)
+      #define XZ_SIDE_AD XY_SIDE_AD
+    #endif
+    constexpr float XZ_SKEW_FACTOR = (
+      #if defined(XZ_DIAG_AC) && defined(XZ_DIAG_BD) && defined(XZ_SIDE_AD)
+        _SKEW_FACTOR(XZ_DIAG_AC, XZ_DIAG_BD, XZ_SIDE_AD)
+      #else
+        0.0
+      #endif
+    );
+  #endif
+  #ifndef YZ_SKEW_FACTOR
+    constexpr float YZ_SKEW_FACTOR = (
+      #if defined(YZ_DIAG_AC) && defined(YZ_DIAG_BD) && defined(YZ_SIDE_AD)
+        _SKEW_FACTOR(YZ_DIAG_AC, YZ_DIAG_BD, YZ_SIDE_AD)
+      #else
+        0.0
+      #endif
+    );
+  #endif
+#endif // SKEW_CORRECTION
+
 /**
  * Heater & Fan Pausing
  */
diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h
index ab1ccd20cd1..c093e0fc62b 100644
--- a/Marlin/src/inc/SanityCheck.h
+++ b/Marlin/src/inc/SanityCheck.h
@@ -1483,4 +1483,18 @@ static_assert(COUNT(sanity_arr_3) <= XYZE_N, "DEFAULT_MAX_ACCELERATION has too m
   #error "LED_CONTROL_MENU requires an LCD controller."
 #endif
 
+#if ENABLED(SKEW_CORRECTION)
+  #if !defined(XY_SKEW_FACTOR) && !(defined(XY_DIAG_AC) && defined(XY_DIAG_BD) && defined(XY_SIDE_AD))
+    #error "SKEW_CORRECTION requires XY_SKEW_FACTOR or XY_DIAG_AC, XY_DIAG_BD, XY_SIDE_AD."
+  #endif
+  #if ENABLED(SKEW_CORRECTION_FOR_Z)
+    #if !defined(XZ_SKEW_FACTOR) && !(defined(XZ_DIAG_AC) && defined(XZ_DIAG_BD) && defined(XZ_SIDE_AD))
+      #error "SKEW_CORRECTION requires XZ_SKEW_FACTOR or XZ_DIAG_AC, XZ_DIAG_BD, XZ_SIDE_AD."
+    #endif
+    #if !defined(YZ_SKEW_FACTOR) && !(defined(YZ_DIAG_AC) && defined(YZ_DIAG_BD) && defined(YZ_SIDE_AD))
+      #error "SKEW_CORRECTION requires YZ_SKEW_FACTOR or YZ_DIAG_AC, YZ_DIAG_BD, YZ_SIDE_AD."
+    #endif
+  #endif
+#endif
+
 #endif // _SANITYCHECK_H_
diff --git a/Marlin/src/lcd/language/language_en.h b/Marlin/src/lcd/language/language_en.h
index f27a3568e63..dcf8f1dcc00 100644
--- a/Marlin/src/lcd/language/language_en.h
+++ b/Marlin/src/lcd/language/language_en.h
@@ -698,6 +698,9 @@
 #ifndef MSG_ZPROBE_OUT
   #define MSG_ZPROBE_OUT                      _UxGT("Z probe out. bed")
 #endif
+#ifndef MSG_SKEW_FACTOR
+  #define MSG_SKEW_FACTOR                     _UxGT("Skew Factor")
+#endif
 #ifndef MSG_BLTOUCH
   #define MSG_BLTOUCH                         _UxGT("BLTouch")
 #endif
diff --git a/Marlin/src/module/configuration_store.cpp b/Marlin/src/module/configuration_store.cpp
index c2239c6c3a7..bd313caab55 100644
--- a/Marlin/src/module/configuration_store.cpp
+++ b/Marlin/src/module/configuration_store.cpp
@@ -36,13 +36,13 @@
  *
  */
 
-#define EEPROM_VERSION "V45"
+#define EEPROM_VERSION "V46"
 
 // Change EEPROM version if these are changed:
 #define EEPROM_OFFSET 100
 
 /**
- * V45 EEPROM Layout:
+ * V46 EEPROM Layout:
  *
  *  100  Version                                    (char x4)
  *  104  EEPROM CRC16                               (uint16_t)
@@ -166,8 +166,13 @@
  * CNC_COORDINATE_SYSTEMS                           108 bytes
  *  602  G54-G59.3 coordinate_system                (float x 27)
  *
- *  710                                   Minimum end-point
- * 2239 (710 + 208 + 36 + 9 + 288 + 988)  Maximum end-point
+ * SKEW_CORRECTION:                                 12 bytes
+ *  710  M852 I    planner.xy_skew_factor           (float)
+ *  714  M852 J    planner.xz_skew_factor           (float)
+ *  718  M852 K    planner.yz_skew_factor           (float)
+ *
+ *  722                                   Minimum end-point
+ * 2251 (722 + 208 + 36 + 9 + 288 + 988)  Maximum end-point
  *
  * ========================================================================
  * meshes_begin (between max and min end-point, directly above)
@@ -633,6 +638,10 @@ void MarlinSettings::postprocess() {
       for (uint8_t q = 3; q--;) EEPROM_WRITE(dummyui32);
     #endif
 
+    //
+    // CNC Coordinate Systems
+    //
+
     #if ENABLED(CNC_COORDINATE_SYSTEMS)
       EEPROM_WRITE(coordinate_system); // 27 floats
     #else
@@ -640,6 +649,19 @@ void MarlinSettings::postprocess() {
       for (uint8_t q = 27; q--;) EEPROM_WRITE(dummy);
     #endif
 
+    //
+    // Skew correction factors
+    //
+
+    #if ENABLED(SKEW_CORRECTION)
+      EEPROM_WRITE(planner.xy_skew_factor);
+      EEPROM_WRITE(planner.xz_skew_factor);
+      EEPROM_WRITE(planner.yz_skew_factor);
+    #else
+      dummy = 0.0f;
+      for (uint8_t q = 3; q--;) EEPROM_WRITE(dummy);
+    #endif
+
     if (!eeprom_error) {
       #if ENABLED(EEPROM_CHITCHAT)
         const int eeprom_size = eeprom_index;
@@ -1078,6 +1100,23 @@ void MarlinSettings::postprocess() {
         for (uint8_t q = 27; q--;) EEPROM_READ(dummy);
       #endif
 
+      //
+      // Skew correction factors
+      //
+
+      #if ENABLED(SKEW_CORRECTION_GCODE)
+        EEPROM_READ(planner.xy_skew_factor);
+        #if ENABLED(SKEW_CORRECTION_FOR_Z)
+          EEPROM_READ(planner.xz_skew_factor);
+          EEPROM_READ(planner.yz_skew_factor);
+        #else
+          EEPROM_READ(dummy);
+          EEPROM_READ(dummy);
+        #endif
+      #else
+        for (uint8_t q = 3; q--;) EEPROM_READ(dummy);
+      #endif
+
       if (working_crc == stored_crc) {
         postprocess();
         #if ENABLED(EEPROM_CHITCHAT)
@@ -1463,6 +1502,14 @@ void MarlinSettings::reset() {
     ubl.reset();
   #endif
 
+  #if ENABLED(SKEW_CORRECTION_GCODE)
+    planner.xy_skew_factor = XY_SKEW_FACTOR;
+    #if ENABLED(SKEW_CORRECTION_FOR_Z)
+      planner.xz_skew_factor = XZ_SKEW_FACTOR;
+      planner.yz_skew_factor = YZ_SKEW_FACTOR;
+    #endif
+  #endif
+
   postprocess();
 
   #if ENABLED(EEPROM_CHITCHAT)
@@ -1887,6 +1934,24 @@ void MarlinSettings::reset() {
       SERIAL_ECHOLNPAIR("  M851 Z", LINEAR_UNIT(zprobe_zoffset));
     #endif
 
+    /**
+     * Bed Skew Correction
+     */
+    #if ENABLED(SKEW_CORRECTION_GCODE)
+      if (!forReplay) {
+        CONFIG_ECHO_START;
+        SERIAL_ECHOLNPGM("Skew Factor: ");
+      }
+      CONFIG_ECHO_START;
+      #if ENABLED(SKEW_CORRECTION_FOR_Z)
+        SERIAL_ECHOPAIR("  M852 I", LINEAR_UNIT(planner.xy_skew_factor));
+        SERIAL_ECHOPAIR(" J", LINEAR_UNIT(planner.xz_skew_factor));
+        SERIAL_ECHOLNPAIR(" K", LINEAR_UNIT(planner.yz_skew_factor));
+      #else
+        SERIAL_ECHOLNPAIR("  M852 S", LINEAR_UNIT(planner.xy_skew_factor));
+      #endif
+    #endif
+
     /**
      * TMC2130 stepper driver current
      */
diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp
index a7e211aa3e1..9b0fe167caa 100644
--- a/Marlin/src/module/planner.cpp
+++ b/Marlin/src/module/planner.cpp
@@ -135,6 +135,20 @@ float Planner::min_feedrate_mm_s,
   #endif
 #endif
 
+#if ENABLED(SKEW_CORRECTION)
+  #if ENABLED(SKEW_CORRECTION_GCODE)
+    // Initialized by settings.load()
+    float Planner::xy_skew_factor;
+    #if ENABLED(SKEW_CORRECTION_FOR_Z)
+      float Planner::xz_skew_factor, Planner::yz_skew_factor;
+    #else
+      constexpr float Planner::xz_skew_factor, Planner::yz_skew_factor;
+    #endif
+  #else
+    constexpr float Planner::xy_skew_factor, Planner::xz_skew_factor, Planner::yz_skew_factor;
+  #endif
+#endif
+
 #if ENABLED(AUTOTEMP)
   float Planner::autotemp_max = 250,
         Planner::autotemp_min = 210,
@@ -565,6 +579,19 @@ void Planner::calculate_volumetric_multipliers() {
    */
   void Planner::apply_leveling(float &rx, float &ry, float &rz) {
 
+    #if ENABLED(SKEW_CORRECTION)
+      if (WITHIN(rx, X_MIN_POS + 1, X_MAX_POS) && WITHIN(ry, Y_MIN_POS + 1, Y_MAX_POS)) {
+        const float tempry = ry - (rz * planner.yz_skew_factor),
+                    temprx = rx - (ry * planner.xy_skew_factor) - (rz * (planner.xz_skew_factor - (planner.xy_skew_factor * planner.yz_skew_factor)));
+        if (WITHIN(temprx, X_MIN_POS, X_MAX_POS) && WITHIN(tempry, Y_MIN_POS, Y_MAX_POS)) {
+          rx = temprx;
+          ry = tempry;
+        }
+        else
+          SERIAL_ECHOLN(MSG_SKEW_WARN);
+      }
+    #endif
+
     if (!leveling_active) return;
 
     #if ABL_PLANAR
@@ -611,45 +638,56 @@ void Planner::calculate_volumetric_multipliers() {
 
   void Planner::unapply_leveling(float raw[XYZ]) {
 
-    if (!leveling_active) return;
-
-    #if ABL_PLANAR
-
-      matrix_3x3 inverse = matrix_3x3::transpose(bed_level_matrix);
-
-      float dx = raw[X_AXIS] - (X_TILT_FULCRUM),
-            dy = raw[Y_AXIS] - (Y_TILT_FULCRUM);
-
-      apply_rotation_xyz(inverse, dx, dy, raw[Z_AXIS]);
-
-      raw[X_AXIS] = dx + X_TILT_FULCRUM;
-      raw[Y_AXIS] = dy + Y_TILT_FULCRUM;
-
+    #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
+      const float fade_scaling_factor = fade_scaling_factor_for_z(raw[Z_AXIS]);
     #else
+      constexpr float fade_scaling_factor = 1.0;
+    #endif
 
-      #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
-        const float fade_scaling_factor = fade_scaling_factor_for_z(raw[Z_AXIS]);
-        if (!fade_scaling_factor) return;
-      #elif HAS_MESH
-        constexpr float fade_scaling_factor = 1.0;
-      #endif
+    if (leveling_active && fade_scaling_factor) {
 
-      raw[Z_AXIS] -= (
-        #if ENABLED(AUTO_BED_LEVELING_UBL)
-          ubl.get_z_correction(raw[X_AXIS], raw[Y_AXIS]) * fade_scaling_factor
-        #elif ENABLED(MESH_BED_LEVELING)
-          mbl.get_z(raw[X_AXIS], raw[Y_AXIS]
-            #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
-              , fade_scaling_factor
-            #endif
-          )
-        #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
-          bilinear_z_offset(raw) * fade_scaling_factor
-        #else
-          0
-        #endif
-      );
+      #if ABL_PLANAR
 
+        matrix_3x3 inverse = matrix_3x3::transpose(bed_level_matrix);
+
+        float dx = raw[X_AXIS] - (X_TILT_FULCRUM),
+              dy = raw[Y_AXIS] - (Y_TILT_FULCRUM);
+
+        apply_rotation_xyz(inverse, dx, dy, raw[Z_AXIS]);
+
+        raw[X_AXIS] = dx + X_TILT_FULCRUM;
+        raw[Y_AXIS] = dy + Y_TILT_FULCRUM;
+
+      #else // !ABL_PLANAR
+
+        raw[Z_AXIS] -= (
+          #if ENABLED(AUTO_BED_LEVELING_UBL)
+            ubl.get_z_correction(raw[X_AXIS], raw[Y_AXIS]) * fade_scaling_factor
+          #elif ENABLED(MESH_BED_LEVELING)
+            mbl.get_z(raw[X_AXIS], raw[Y_AXIS]
+              #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
+                , fade_scaling_factor
+              #endif
+            )
+          #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
+            bilinear_z_offset(raw) * fade_scaling_factor
+          #else
+            0
+          #endif
+        );
+
+      #endif // !ABL_PLANAR
+    }
+
+    #if ENABLED(SKEW_CORRECTION)
+      if (WITHIN(raw[X_AXIS], X_MIN_POS, X_MAX_POS) && WITHIN(raw[Y_AXIS], Y_MIN_POS, Y_MAX_POS)) {
+        const float temprx = raw[X_AXIS] + raw[Y_AXIS] * planner.xy_skew_factor + raw[Z_AXIS] * planner.xz_skew_factor,
+                    tempry = raw[Y_AXIS] + raw[Z_AXIS] * planner.yz_skew_factor;
+        if (WITHIN(temprx, X_MIN_POS, X_MAX_POS) && WITHIN(tempry, Y_MIN_POS, Y_MAX_POS)) {
+          raw[X_AXIS] = temprx;
+          raw[Y_AXIS] = tempry;
+        }
+      }
     #endif
   }
 
@@ -658,13 +696,13 @@ void Planner::calculate_volumetric_multipliers() {
 /**
  * Planner::_buffer_line
  *
- * Add a new linear movement to the buffer.
+ * Add a new linear movement to the buffer in axis units.
  *
  * Leveling and kinematics should be applied ahead of calling this.
  *
- *  a,b,c,e     - target positions in mm or degrees
- *  fr_mm_s     - (target) speed of the move
- *  extruder    - target extruder
+ *  a,b,c,e   - target positions in mm and/or degrees
+ *  fr_mm_s   - (target) speed of the move
+ *  extruder  - target extruder
  */
 void Planner::_buffer_line(const float &a, const float &b, const float &c, const float &e, float fr_mm_s, const uint8_t extruder) {
 
@@ -713,6 +751,10 @@ void Planner::_buffer_line(const float &a, const float &b, const float &c, const
   SERIAL_EOL();
   //*/
 
+  // DRYRUN ignores all temperature constraints and assures that the extruder is instantly satisfied
+  if (DEBUGGING(DRYRUN))
+    position[E_AXIS] = target[E_AXIS];
+
   int32_t de = target[E_AXIS] - position[E_AXIS];
 
   #if ENABLED(PREVENT_COLD_EXTRUSION) || ENABLED(PREVENT_LENGTHY_EXTRUDE)
@@ -736,6 +778,10 @@ void Planner::_buffer_line(const float &a, const float &b, const float &c, const
     }
   #endif // PREVENT_COLD_EXTRUSION || PREVENT_LENGTHY_EXTRUDE
 
+  #if ENABLED(LIN_ADVANCE)
+    float de_float = de * steps_to_mm[E_AXIS_N];
+  #endif
+
   // Compute direction bit-mask for this block
   uint8_t dm = 0;
   #if CORE_IS_XY
@@ -1332,6 +1378,7 @@ void Planner::_buffer_line(const float &a, const float &b, const float &c, const
   previous_safe_speed = safe_speed;
 
   #if ENABLED(LIN_ADVANCE)
+
     /**
      *
      * Use LIN_ADVANCE for blocks if all these are true:
diff --git a/Marlin/src/module/planner.h b/Marlin/src/module/planner.h
index b89655d3c5b..070e75c012f 100644
--- a/Marlin/src/module/planner.h
+++ b/Marlin/src/module/planner.h
@@ -180,6 +180,23 @@ class Planner {
       static float extruder_advance_k, advance_ed_ratio;
     #endif
 
+    #if ENABLED(SKEW_CORRECTION)
+      #if ENABLED(SKEW_CORRECTION_GCODE)
+        static float xy_skew_factor;
+      #else
+        static constexpr float xy_skew_factor = XY_SKEW_FACTOR;
+      #endif
+      #if ENABLED(SKEW_CORRECTION_FOR_Z)
+        #if ENABLED(SKEW_CORRECTION_GCODE)
+          static float xz_skew_factor, yz_skew_factor;
+        #else
+          static constexpr float xz_skew_factor = XZ_SKEW_FACTOR, yz_skew_factor = YZ_SKEW_FACTOR;
+        #endif
+      #else
+        static constexpr float xz_skew_factor = 0, yz_skew_factor = 0;
+      #endif
+    #endif
+
   private:
 
     /**