diff --git a/doc/classes/NavigationLink2D.xml b/doc/classes/NavigationLink2D.xml
index 0892c9ec440..2e1c962dd15 100644
--- a/doc/classes/NavigationLink2D.xml
+++ b/doc/classes/NavigationLink2D.xml
@@ -29,6 +29,12 @@
 				Returns whether or not the specified layer of the [member navigation_layers] bitmask is enabled, given a [param layer_number] between 1 and 32.
 			</description>
 		</method>
+		<method name="get_navigation_map" qualifiers="const">
+			<return type="RID" />
+			<description>
+				Returns the current navigation map [RID] used by this link.
+			</description>
+		</method>
 		<method name="get_rid" qualifiers="const">
 			<return type="RID" />
 			<description>
@@ -57,6 +63,13 @@
 				Based on [param value], enables or disables the specified layer in the [member navigation_layers] bitmask, given a [param layer_number] between 1 and 32.
 			</description>
 		</method>
+		<method name="set_navigation_map">
+			<return type="void" />
+			<param index="0" name="navigation_map" type="RID" />
+			<description>
+				Sets the [RID] of the navigation map this link should use. By default the link will automatically join the [World2D] default navigation map so this function is only required to override the default map.
+			</description>
+		</method>
 	</methods>
 	<members>
 		<member name="bidirectional" type="bool" setter="set_bidirectional" getter="is_bidirectional" default="true">
diff --git a/doc/classes/NavigationLink3D.xml b/doc/classes/NavigationLink3D.xml
index 0fcc106beb7..174228ea5b2 100644
--- a/doc/classes/NavigationLink3D.xml
+++ b/doc/classes/NavigationLink3D.xml
@@ -29,6 +29,12 @@
 				Returns whether or not the specified layer of the [member navigation_layers] bitmask is enabled, given a [param layer_number] between 1 and 32.
 			</description>
 		</method>
+		<method name="get_navigation_map" qualifiers="const">
+			<return type="RID" />
+			<description>
+				Returns the current navigation map [RID] used by this link.
+			</description>
+		</method>
 		<method name="get_rid" qualifiers="const">
 			<return type="RID" />
 			<description>
@@ -57,6 +63,13 @@
 				Based on [param value], enables or disables the specified layer in the [member navigation_layers] bitmask, given a [param layer_number] between 1 and 32.
 			</description>
 		</method>
+		<method name="set_navigation_map">
+			<return type="void" />
+			<param index="0" name="navigation_map" type="RID" />
+			<description>
+				Sets the [RID] of the navigation map this link should use. By default the link will automatically join the [World3D] default navigation map so this function is only required to override the default map.
+			</description>
+		</method>
 	</methods>
 	<members>
 		<member name="bidirectional" type="bool" setter="set_bidirectional" getter="is_bidirectional" default="true">
diff --git a/scene/2d/navigation_link_2d.cpp b/scene/2d/navigation_link_2d.cpp
index 04ba550888a..111f5a7b78c 100644
--- a/scene/2d/navigation_link_2d.cpp
+++ b/scene/2d/navigation_link_2d.cpp
@@ -41,6 +41,9 @@ void NavigationLink2D::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &NavigationLink2D::set_enabled);
 	ClassDB::bind_method(D_METHOD("is_enabled"), &NavigationLink2D::is_enabled);
 
+	ClassDB::bind_method(D_METHOD("set_navigation_map", "navigation_map"), &NavigationLink2D::set_navigation_map);
+	ClassDB::bind_method(D_METHOD("get_navigation_map"), &NavigationLink2D::get_navigation_map);
+
 	ClassDB::bind_method(D_METHOD("set_bidirectional", "bidirectional"), &NavigationLink2D::set_bidirectional);
 	ClassDB::bind_method(D_METHOD("is_bidirectional"), &NavigationLink2D::is_bidirectional);
 
@@ -106,12 +109,7 @@ bool NavigationLink2D::_get(const StringName &p_name, Variant &r_ret) const {
 void NavigationLink2D::_notification(int p_what) {
 	switch (p_what) {
 		case NOTIFICATION_ENTER_TREE: {
-			if (enabled) {
-				NavigationServer2D::get_singleton()->link_set_map(link, get_world_2d()->get_navigation_map());
-			}
-			current_global_transform = get_global_transform();
-			NavigationServer2D::get_singleton()->link_set_start_position(link, current_global_transform.xform(start_position));
-			NavigationServer2D::get_singleton()->link_set_end_position(link, current_global_transform.xform(end_position));
+			_link_enter_navigation_map();
 		} break;
 
 		case NOTIFICATION_TRANSFORM_CHANGED: {
@@ -120,36 +118,15 @@ void NavigationLink2D::_notification(int p_what) {
 
 		case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
 			set_physics_process_internal(false);
-			if (is_inside_tree()) {
-				Transform2D new_global_transform = get_global_transform();
-				if (current_global_transform != new_global_transform) {
-					current_global_transform = new_global_transform;
-					NavigationServer2D::get_singleton()->link_set_start_position(link, current_global_transform.xform(start_position));
-					NavigationServer2D::get_singleton()->link_set_end_position(link, current_global_transform.xform(end_position));
-					queue_redraw();
-				}
-			}
+			_link_update_transform();
 		} break;
 
 		case NOTIFICATION_EXIT_TREE: {
-			NavigationServer2D::get_singleton()->link_set_map(link, RID());
+			_link_exit_navigation_map();
 		} break;
 		case NOTIFICATION_DRAW: {
 #ifdef DEBUG_ENABLED
-			if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || NavigationServer2D::get_singleton()->get_debug_enabled())) {
-				Color color;
-				if (enabled) {
-					color = NavigationServer2D::get_singleton()->get_debug_navigation_link_connection_color();
-				} else {
-					color = NavigationServer2D::get_singleton()->get_debug_navigation_link_connection_disabled_color();
-				}
-
-				real_t radius = NavigationServer2D::get_singleton()->map_get_link_connection_radius(get_world_2d()->get_navigation_map());
-
-				draw_line(get_start_position(), get_end_position(), color);
-				draw_arc(get_start_position(), radius, 0, Math_TAU, 10, color);
-				draw_arc(get_end_position(), radius, 0, Math_TAU, 10, color);
-			}
+			_update_debug_mesh();
 #endif // DEBUG_ENABLED
 		} break;
 	}
@@ -188,15 +165,32 @@ void NavigationLink2D::set_enabled(bool p_enabled) {
 
 	enabled = p_enabled;
 
-	NavigationServer3D::get_singleton()->link_set_enabled(link, enabled);
+	NavigationServer2D::get_singleton()->link_set_enabled(link, enabled);
 
 #ifdef DEBUG_ENABLED
-	if (Engine::get_singleton()->is_editor_hint() || NavigationServer2D::get_singleton()->get_debug_enabled()) {
-		queue_redraw();
-	}
+	queue_redraw();
 #endif // DEBUG_ENABLED
 }
 
+void NavigationLink2D::set_navigation_map(RID p_navigation_map) {
+	if (map_override == p_navigation_map) {
+		return;
+	}
+
+	map_override = p_navigation_map;
+
+	NavigationServer2D::get_singleton()->link_set_map(link, map_override);
+}
+
+RID NavigationLink2D::get_navigation_map() const {
+	if (map_override.is_valid()) {
+		return map_override;
+	} else if (is_inside_tree()) {
+		return get_world_2d()->get_navigation_map();
+	}
+	return RID();
+}
+
 void NavigationLink2D::set_bidirectional(bool p_bidirectional) {
 	if (bidirectional == p_bidirectional) {
 		return;
@@ -255,9 +249,7 @@ void NavigationLink2D::set_start_position(Vector2 p_position) {
 	update_configuration_warnings();
 
 #ifdef DEBUG_ENABLED
-	if (Engine::get_singleton()->is_editor_hint() || NavigationServer2D::get_singleton()->get_debug_enabled()) {
-		queue_redraw();
-	}
+	queue_redraw();
 #endif // DEBUG_ENABLED
 }
 
@@ -277,9 +269,7 @@ void NavigationLink2D::set_end_position(Vector2 p_position) {
 	update_configuration_warnings();
 
 #ifdef DEBUG_ENABLED
-	if (Engine::get_singleton()->is_editor_hint() || NavigationServer2D::get_singleton()->get_debug_enabled()) {
-		queue_redraw();
-	}
+	queue_redraw();
 #endif // DEBUG_ENABLED
 }
 
@@ -347,6 +337,69 @@ PackedStringArray NavigationLink2D::get_configuration_warnings() const {
 	return warnings;
 }
 
+void NavigationLink2D::_link_enter_navigation_map() {
+	if (!is_inside_tree()) {
+		return;
+	}
+
+	if (map_override.is_valid()) {
+		NavigationServer2D::get_singleton()->link_set_map(link, map_override);
+	} else {
+		NavigationServer2D::get_singleton()->link_set_map(link, get_world_2d()->get_navigation_map());
+	}
+
+	current_global_transform = get_global_transform();
+
+	NavigationServer2D::get_singleton()->link_set_start_position(link, current_global_transform.xform(start_position));
+	NavigationServer2D::get_singleton()->link_set_end_position(link, current_global_transform.xform(end_position));
+	NavigationServer2D::get_singleton()->link_set_enabled(link, enabled);
+
+	queue_redraw();
+}
+
+void NavigationLink2D::_link_exit_navigation_map() {
+	NavigationServer2D::get_singleton()->link_set_map(link, RID());
+}
+
+void NavigationLink2D::_link_update_transform() {
+	if (!is_inside_tree()) {
+		return;
+	}
+
+	Transform2D new_global_transform = get_global_transform();
+	if (current_global_transform != new_global_transform) {
+		current_global_transform = new_global_transform;
+		NavigationServer2D::get_singleton()->link_set_start_position(link, current_global_transform.xform(start_position));
+		NavigationServer2D::get_singleton()->link_set_end_position(link, current_global_transform.xform(end_position));
+		queue_redraw();
+	}
+}
+
+#ifdef DEBUG_ENABLED
+void NavigationLink2D::_update_debug_mesh() {
+	if (!is_inside_tree()) {
+		return;
+	}
+
+	if (!Engine::get_singleton()->is_editor_hint() && !NavigationServer2D::get_singleton()->get_debug_enabled()) {
+		return;
+	}
+
+	Color color;
+	if (enabled) {
+		color = NavigationServer2D::get_singleton()->get_debug_navigation_link_connection_color();
+	} else {
+		color = NavigationServer2D::get_singleton()->get_debug_navigation_link_connection_disabled_color();
+	}
+
+	real_t radius = NavigationServer2D::get_singleton()->map_get_link_connection_radius(get_world_2d()->get_navigation_map());
+
+	draw_line(get_start_position(), get_end_position(), color);
+	draw_arc(get_start_position(), radius, 0, Math_TAU, 10, color);
+	draw_arc(get_end_position(), radius, 0, Math_TAU, 10, color);
+}
+#endif // DEBUG_ENABLED
+
 NavigationLink2D::NavigationLink2D() {
 	link = NavigationServer2D::get_singleton()->link_create();
 
diff --git a/scene/2d/navigation_link_2d.h b/scene/2d/navigation_link_2d.h
index 2929691c045..c724096607d 100644
--- a/scene/2d/navigation_link_2d.h
+++ b/scene/2d/navigation_link_2d.h
@@ -38,6 +38,7 @@ class NavigationLink2D : public Node2D {
 
 	bool enabled = true;
 	RID link;
+	RID map_override;
 	bool bidirectional = true;
 	uint32_t navigation_layers = 1;
 	Vector2 end_position;
@@ -47,6 +48,10 @@ class NavigationLink2D : public Node2D {
 
 	Transform2D current_global_transform;
 
+#ifdef DEBUG_ENABLED
+	void _update_debug_mesh();
+#endif // DEBUG_ENABLED
+
 protected:
 	static void _bind_methods();
 	void _notification(int p_what);
@@ -66,6 +71,9 @@ class NavigationLink2D : public Node2D {
 	void set_enabled(bool p_enabled);
 	bool is_enabled() const { return enabled; }
 
+	void set_navigation_map(RID p_navigation_map);
+	RID get_navigation_map() const;
+
 	void set_bidirectional(bool p_bidirectional);
 	bool is_bidirectional() const { return bidirectional; }
 
@@ -97,6 +105,11 @@ class NavigationLink2D : public Node2D {
 
 	NavigationLink2D();
 	~NavigationLink2D();
+
+private:
+	void _link_enter_navigation_map();
+	void _link_exit_navigation_map();
+	void _link_update_transform();
 };
 
 #endif // NAVIGATION_LINK_2D_H
diff --git a/scene/3d/navigation_link_3d.cpp b/scene/3d/navigation_link_3d.cpp
index dc776ebea25..bebba9a6c04 100644
--- a/scene/3d/navigation_link_3d.cpp
+++ b/scene/3d/navigation_link_3d.cpp
@@ -152,6 +152,9 @@ void NavigationLink3D::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &NavigationLink3D::set_enabled);
 	ClassDB::bind_method(D_METHOD("is_enabled"), &NavigationLink3D::is_enabled);
 
+	ClassDB::bind_method(D_METHOD("set_navigation_map", "navigation_map"), &NavigationLink3D::set_navigation_map);
+	ClassDB::bind_method(D_METHOD("get_navigation_map"), &NavigationLink3D::get_navigation_map);
+
 	ClassDB::bind_method(D_METHOD("set_bidirectional", "bidirectional"), &NavigationLink3D::set_bidirectional);
 	ClassDB::bind_method(D_METHOD("is_bidirectional"), &NavigationLink3D::is_bidirectional);
 
@@ -217,16 +220,7 @@ bool NavigationLink3D::_get(const StringName &p_name, Variant &r_ret) const {
 void NavigationLink3D::_notification(int p_what) {
 	switch (p_what) {
 		case NOTIFICATION_ENTER_TREE: {
-			if (enabled) {
-				NavigationServer3D::get_singleton()->link_set_map(link, get_world_3d()->get_navigation_map());
-			}
-			current_global_transform = get_global_transform();
-			NavigationServer3D::get_singleton()->link_set_start_position(link, current_global_transform.xform(start_position));
-			NavigationServer3D::get_singleton()->link_set_end_position(link, current_global_transform.xform(end_position));
-
-#ifdef DEBUG_ENABLED
-			_update_debug_mesh();
-#endif // DEBUG_ENABLED
+			_link_enter_navigation_map();
 		} break;
 
 		case NOTIFICATION_TRANSFORM_CHANGED: {
@@ -235,30 +229,11 @@ void NavigationLink3D::_notification(int p_what) {
 
 		case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
 			set_physics_process_internal(false);
-			if (is_inside_tree()) {
-				Transform3D new_global_transform = get_global_transform();
-				if (current_global_transform != new_global_transform) {
-					current_global_transform = new_global_transform;
-					NavigationServer3D::get_singleton()->link_set_start_position(link, current_global_transform.xform(start_position));
-					NavigationServer3D::get_singleton()->link_set_end_position(link, current_global_transform.xform(end_position));
-#ifdef DEBUG_ENABLED
-					if (debug_instance.is_valid()) {
-						RS::get_singleton()->instance_set_transform(debug_instance, current_global_transform);
-					}
-#endif // DEBUG_ENABLED
-				}
-			}
+			_link_update_transform();
 		} break;
 
 		case NOTIFICATION_EXIT_TREE: {
-			NavigationServer3D::get_singleton()->link_set_map(link, RID());
-
-#ifdef DEBUG_ENABLED
-			if (debug_instance.is_valid()) {
-				RS::get_singleton()->instance_set_scenario(debug_instance, RID());
-				RS::get_singleton()->instance_set_visible(debug_instance, false);
-			}
-#endif // DEBUG_ENABLED
+			_link_exit_navigation_map();
 		} break;
 	}
 }
@@ -320,6 +295,25 @@ void NavigationLink3D::set_enabled(bool p_enabled) {
 	update_gizmos();
 }
 
+void NavigationLink3D::set_navigation_map(RID p_navigation_map) {
+	if (map_override == p_navigation_map) {
+		return;
+	}
+
+	map_override = p_navigation_map;
+
+	NavigationServer3D::get_singleton()->link_set_map(link, map_override);
+}
+
+RID NavigationLink3D::get_navigation_map() const {
+	if (map_override.is_valid()) {
+		return map_override;
+	} else if (is_inside_tree()) {
+		return get_world_3d()->get_navigation_map();
+	}
+	return RID();
+}
+
 void NavigationLink3D::set_bidirectional(bool p_bidirectional) {
 	if (bidirectional == p_bidirectional) {
 		return;
@@ -467,3 +461,53 @@ PackedStringArray NavigationLink3D::get_configuration_warnings() const {
 
 	return warnings;
 }
+
+void NavigationLink3D::_link_enter_navigation_map() {
+	if (!is_inside_tree()) {
+		return;
+	}
+
+	if (map_override.is_valid()) {
+		NavigationServer3D::get_singleton()->link_set_map(link, map_override);
+	} else {
+		NavigationServer3D::get_singleton()->link_set_map(link, get_world_3d()->get_navigation_map());
+	}
+
+	current_global_transform = get_global_transform();
+	NavigationServer3D::get_singleton()->link_set_start_position(link, current_global_transform.xform(start_position));
+	NavigationServer3D::get_singleton()->link_set_end_position(link, current_global_transform.xform(end_position));
+	NavigationServer3D::get_singleton()->link_set_enabled(link, enabled);
+
+#ifdef DEBUG_ENABLED
+	if (NavigationServer3D::get_singleton()->get_debug_navigation_enabled()) {
+		_update_debug_mesh();
+	}
+#endif // DEBUG_ENABLED
+}
+
+void NavigationLink3D::_link_exit_navigation_map() {
+	NavigationServer3D::get_singleton()->link_set_map(link, RID());
+#ifdef DEBUG_ENABLED
+	if (debug_instance.is_valid()) {
+		RS::get_singleton()->instance_set_visible(debug_instance, false);
+	}
+#endif // DEBUG_ENABLED
+}
+
+void NavigationLink3D::_link_update_transform() {
+	if (!is_inside_tree()) {
+		return;
+	}
+
+	Transform3D new_global_transform = get_global_transform();
+	if (current_global_transform != new_global_transform) {
+		current_global_transform = new_global_transform;
+		NavigationServer3D::get_singleton()->link_set_start_position(link, current_global_transform.xform(start_position));
+		NavigationServer3D::get_singleton()->link_set_end_position(link, current_global_transform.xform(end_position));
+#ifdef DEBUG_ENABLED
+		if (NavigationServer3D::get_singleton()->get_debug_navigation_enabled()) {
+			_update_debug_mesh();
+		}
+#endif // DEBUG_ENABLED
+	}
+}
diff --git a/scene/3d/navigation_link_3d.h b/scene/3d/navigation_link_3d.h
index 1867082811f..e894761f400 100644
--- a/scene/3d/navigation_link_3d.h
+++ b/scene/3d/navigation_link_3d.h
@@ -38,6 +38,7 @@ class NavigationLink3D : public Node3D {
 
 	bool enabled = true;
 	RID link;
+	RID map_override;
 	bool bidirectional = true;
 	uint32_t navigation_layers = 1;
 	Vector3 end_position;
@@ -72,6 +73,9 @@ class NavigationLink3D : public Node3D {
 	void set_enabled(bool p_enabled);
 	bool is_enabled() const { return enabled; }
 
+	void set_navigation_map(RID p_navigation_map);
+	RID get_navigation_map() const;
+
 	void set_bidirectional(bool p_bidirectional);
 	bool is_bidirectional() const { return bidirectional; }
 
@@ -100,6 +104,11 @@ class NavigationLink3D : public Node3D {
 	real_t get_travel_cost() const { return travel_cost; }
 
 	PackedStringArray get_configuration_warnings() const override;
+
+private:
+	void _link_enter_navigation_map();
+	void _link_exit_navigation_map();
+	void _link_update_transform();
 };
 
 #endif // NAVIGATION_LINK_3D_H