diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp
index 59dc85a0a..52a3335ee 100644
--- a/src/libslic3r/Format/3mf.cpp
+++ b/src/libslic3r/Format/3mf.cpp
@@ -1114,6 +1114,15 @@ namespace Slic3r {
                                                       float(std::atof(object_data_points[i+6].c_str())),
                                                       float(std::atof(object_data_points[i+7].c_str())));
                 }
+
+                // The holes are saved elevated above the mesh and deeper (bad idea indeed).
+                // This is retained for compatibility.
+                // Place the hole to the mesh and make it shallower to compensate.
+                // The offset is 1 mm above the mesh.
+                for (sla::DrainHole& hole : sla_drain_holes) {
+                    hole.pos += hole.normal.normalized();
+                    hole.height -= 1.f;
+                }
                 
                 if (!sla_drain_holes.empty())
                     m_sla_drain_holes.insert(IdToSlaDrainHolesMap::value_type(object_id, sla_drain_holes));
@@ -2591,7 +2600,18 @@ namespace Slic3r {
         for (const ModelObject* object : model.objects)
         {
             ++count;
-            auto& drain_holes = object->sla_drain_holes;
+            sla::DrainHoles drain_holes = object->sla_drain_holes;
+
+            // The holes were placed 1mm above the mesh in the first implementation.
+            // This was a bad idea and the reference point was changed in 2.3 so
+            // to be on the mesh exactly. The elevated position is still saved
+            // in 3MFs for compatibility reasons.
+            for (sla::DrainHole& hole : drain_holes) {
+                hole.pos -= hole.normal.normalized();
+                hole.height += 1.f;
+            }
+
+
             if (!drain_holes.empty())
             {
                 out += string_printf(fmt, count);
diff --git a/src/libslic3r/Format/3mf.hpp b/src/libslic3r/Format/3mf.hpp
index 94a702775..ccfd9356d 100644
--- a/src/libslic3r/Format/3mf.hpp
+++ b/src/libslic3r/Format/3mf.hpp
@@ -35,6 +35,6 @@ namespace Slic3r {
     // The model could be modified during the export process if meshes are not repaired or have no shared vertices
     extern bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config, bool fullpath_sources, const ThumbnailData* thumbnail_data = nullptr);
 
-}; // namespace Slic3r
+} // namespace Slic3r
 
 #endif /* slic3r_Format_3mf_hpp_ */
diff --git a/src/libslic3r/SLA/Hollowing.hpp b/src/libslic3r/SLA/Hollowing.hpp
index c7d27d946..949cc2393 100644
--- a/src/libslic3r/SLA/Hollowing.hpp
+++ b/src/libslic3r/SLA/Hollowing.hpp
@@ -58,6 +58,8 @@ struct DrainHole
 
 using DrainHoles = std::vector<DrainHole>;
 
+constexpr float HoleStickOutLength = 1.f;
+
 std::unique_ptr<TriangleMesh> generate_interior(const TriangleMesh &mesh,
                                                 const HollowingConfig &  = {},
                                                 const JobController &ctl = {});
diff --git a/src/libslic3r/SLA/ReprojectPointsOnMesh.hpp b/src/libslic3r/SLA/ReprojectPointsOnMesh.hpp
index 4737a6c21..20804193e 100644
--- a/src/libslic3r/SLA/ReprojectPointsOnMesh.hpp
+++ b/src/libslic3r/SLA/ReprojectPointsOnMesh.hpp
@@ -28,15 +28,9 @@ void reproject_support_points(const IndexedMesh &mesh, std::vector<PointType> &p
 inline void reproject_points_and_holes(ModelObject *object)
 {
     bool has_sppoints = !object->sla_support_points.empty();
+    bool has_holes    = !object->sla_drain_holes.empty();
 
-    // Disabling reprojection of holes as they have a significant offset away
-    // from the model body which tolerates minor geometrical changes.
-    //
-    // TODO: uncomment and ensure the right offset of the hole points if
-    // reprojection would still be necessary.
-    // bool has_holes    = !object->sla_drain_holes.empty();
-
-    if (!object || (/*!has_holes &&*/ !has_sppoints)) return;
+    if (!object || (!has_holes && !has_sppoints)) return;
 
     TriangleMesh rmsh = object->raw_mesh();
     rmsh.require_shared_vertices();
@@ -45,8 +39,8 @@ inline void reproject_points_and_holes(ModelObject *object)
     if (has_sppoints)
         reproject_support_points(emesh, object->sla_support_points);
 
-//    if (has_holes)
-//        reproject_support_points(emesh, object->sla_drain_holes);
+    if (has_holes)
+        reproject_support_points(emesh, object->sla_drain_holes);
 }
 
 }}
diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp
index 4395bea46..07ec38016 100644
--- a/src/libslic3r/SLAPrint.cpp
+++ b/src/libslic3r/SLAPrint.cpp
@@ -1181,6 +1181,12 @@ sla::DrainHoles SLAPrintObject::transformed_drainhole_points() const
         hl.normal = Vec3f(hl.normal(0)/(sc(0)*sc(0)),
                           hl.normal(1)/(sc(1)*sc(1)),
                           hl.normal(2)/(sc(2)*sc(2)));
+
+        // Now shift the hole a bit above the object and make it deeper to
+        // compensate for it. This is to avoid problems when the hole is placed
+        // on (nearly) flat surface.
+        hl.pos -= hl.normal.normalized() * sla::HoleStickOutLength;
+        hl.height += sla::HoleStickOutLength;
     }
 
     return pts;
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp
index 273384da2..04ada5253 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp
@@ -130,7 +130,7 @@ void GLGizmoHollow::render_points(const Selection& selection, bool picking) cons
         const sla::DrainHole& drain_hole = drain_holes[i];
         const bool& point_selected = m_selected[i];
 
-        if (is_mesh_point_clipped((drain_hole.pos+HoleStickOutLength*drain_hole.normal).cast<double>()))
+        if (is_mesh_point_clipped(drain_hole.pos.cast<double>()))
             continue;
 
         // First decide about the color of the point.
@@ -174,10 +174,10 @@ void GLGizmoHollow::render_points(const Selection& selection, bool picking) cons
         glsafe(::glRotated(aa.angle() * (180. / M_PI), aa.axis()(0), aa.axis()(1), aa.axis()(2)));
         glsafe(::glPushMatrix());
         glsafe(::glTranslated(0., 0., -drain_hole.height));
-        ::gluCylinder(m_quadric, drain_hole.radius, drain_hole.radius, drain_hole.height, 24, 1);
-        glsafe(::glTranslated(0., 0., drain_hole.height));
+        ::gluCylinder(m_quadric, drain_hole.radius, drain_hole.radius, drain_hole.height + sla::HoleStickOutLength, 24, 1);
+        glsafe(::glTranslated(0., 0., drain_hole.height + sla::HoleStickOutLength));
         ::gluDisk(m_quadric, 0.0, drain_hole.radius, 24, 1);
-        glsafe(::glTranslated(0., 0., -drain_hole.height));
+        glsafe(::glTranslated(0., 0., -drain_hole.height - sla::HoleStickOutLength));
         glsafe(::glRotatef(180.f, 1.f, 0.f, 0.f));
         ::gluDisk(m_quadric, 0.0, drain_hole.radius, 24, 1);
         glsafe(::glPopMatrix());
@@ -307,13 +307,8 @@ bool GLGizmoHollow::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_pos
             if (unproject_on_mesh(mouse_position, pos_and_normal)) { // we got an intersection
                 Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Add drainage hole")));
 
-                Vec3d scaling = mo->instances[active_inst]->get_scaling_factor();
-                Vec3f normal_transformed(pos_and_normal.second(0)/scaling(0),
-                                         pos_and_normal.second(1)/scaling(1),
-                                         pos_and_normal.second(2)/scaling(2));
-
-                mo->sla_drain_holes.emplace_back(pos_and_normal.first + HoleStickOutLength * pos_and_normal.second/* normal_transformed.normalized()*/,
-                                                             -pos_and_normal.second, m_new_hole_radius, m_new_hole_height);
+                mo->sla_drain_holes.emplace_back(pos_and_normal.first,
+                                                -pos_and_normal.second, m_new_hole_radius, m_new_hole_height);
                 m_selected.push_back(false);
                 assert(m_selected.size() == mo->sla_drain_holes.size());
                 m_parent.set_as_dirty();
@@ -447,7 +442,7 @@ void GLGizmoHollow::on_update(const UpdateData& data)
         std::pair<Vec3f, Vec3f> pos_and_normal;
         if (! unproject_on_mesh(data.mouse_pos.cast<double>(), pos_and_normal))
             return;
-        drain_holes[m_hover_id].pos = pos_and_normal.first + HoleStickOutLength * pos_and_normal.second;
+        drain_holes[m_hover_id].pos = pos_and_normal.first;
         drain_holes[m_hover_id].normal = -pos_and_normal.second;
     }
 }
@@ -661,9 +656,7 @@ RENDER_AGAIN:
 
     m_imgui->text(m_desc["hole_depth"]);
     ImGui::SameLine(diameter_slider_left);
-    m_new_hole_height -= HoleStickOutLength;
     ImGui::SliderFloat("  ", &m_new_hole_height, 0.f, 10.f, "%.1f mm");
-    m_new_hole_height += HoleStickOutLength;
 
     clicked |= ImGui::IsItemClicked();
     edited |= ImGui::IsItemEdited();
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
index 2856bb35d..bc29da6d2 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
@@ -222,7 +222,7 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
         render_color[3] = 0.7f;
         glsafe(::glColor4fv(render_color));
         for (const sla::DrainHole& drain_hole : m_c->selection_info()->model_object()->sla_drain_holes) {
-            if (is_mesh_point_clipped((drain_hole.pos+HoleStickOutLength*drain_hole.normal).cast<double>()))
+            if (is_mesh_point_clipped(drain_hole.pos.cast<double>()))
                 continue;
 
             // Inverse matrix of the instance scaling is applied so that the mark does not scale with the object.
@@ -241,10 +241,10 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
             glsafe(::glRotated(aa.angle() * (180. / M_PI), aa.axis()(0), aa.axis()(1), aa.axis()(2)));
             glsafe(::glPushMatrix());
             glsafe(::glTranslated(0., 0., -drain_hole.height));
-            ::gluCylinder(m_quadric, drain_hole.radius, drain_hole.radius, drain_hole.height, 24, 1);
-            glsafe(::glTranslated(0., 0., drain_hole.height));
+            ::gluCylinder(m_quadric, drain_hole.radius, drain_hole.radius, drain_hole.height + sla::HoleStickOutLength, 24, 1);
+            glsafe(::glTranslated(0., 0., drain_hole.height + sla::HoleStickOutLength));
             ::gluDisk(m_quadric, 0.0, drain_hole.radius, 24, 1);
-            glsafe(::glTranslated(0., 0., -drain_hole.height));
+            glsafe(::glTranslated(0., 0., -drain_hole.height - sla::HoleStickOutLength));
             glsafe(::glRotatef(180.f, 1.f, 0.f, 0.f));
             ::gluDisk(m_quadric, 0.0, drain_hole.radius, 24, 1);
             glsafe(::glPopMatrix());
diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp
index 31c473bac..aedf782e8 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp
@@ -15,8 +15,6 @@ namespace GUI {
 
 class GLCanvas3D;
 
-static constexpr float HoleStickOutLength = 1.f;
-
 enum class SLAGizmoEventType : unsigned char {
     LeftDown = 1,
     LeftUp,