diff --git a/doc/user-guide/src/concepts/components.md b/doc/user-guide/src/concepts/components.md
index 59978298b2..f6f35a04ef 100644
--- a/doc/user-guide/src/concepts/components.md
+++ b/doc/user-guide/src/concepts/components.md
@@ -63,6 +63,9 @@ toolchains. The following is an overview of the different components:
 
 ### Previous components
 
+> See [here](https://rust-lang.github.io/rustup/devel/concepts/components.html#previous-components)
+> for the latest version of this section.
+
 These components have been deprecated and are not published in new Rust releases.
 
 * `rls` --- [RLS] is a language server that is deprecated and has been replaced
diff --git a/src/dist/mod.rs b/src/dist/mod.rs
index f9623d8e06..5fe3651767 100644
--- a/src/dist/mod.rs
+++ b/src/dist/mod.rs
@@ -46,14 +46,6 @@ pub(crate) use triple::*;
 
 pub static DEFAULT_DIST_SERVER: &str = "https://static.rust-lang.org";
 
-const TOOLSTATE_MSG: &str =
-    "If you require these components, please install and use the latest successful build version,\n\
-     which you can find at <https://rust-lang.github.io/rustup-components-history>.\n\nAfter determining \
-     the correct date, install it with a command such as:\n\n    \
-     rustup toolchain install nightly-2018-12-27\n\n\
-     Then you can use the toolchain with commands such as:\n\n    \
-     cargo +nightly-2018-12-27 build";
-
 /// Returns a error message indicating that certain [`Component`]s are missing in a toolchain distribution.
 ///
 /// This message is currently used exclusively in toolchain-wide operations,
@@ -63,8 +55,6 @@ const TOOLSTATE_MSG: &str =
 /// This function will panic when the collection of unavailable components `cs` is empty.
 fn components_missing_msg(cs: &[Component], manifest: &ManifestV2, toolchain: &str) -> String {
     let mut buf = vec![];
-    let suggestion = format!("    rustup toolchain add {toolchain} --profile minimal");
-    let nightly_tips = "Sometimes not all components are available in any given nightly. ";
 
     match cs {
         [] => panic!("`components_missing_msg` should not be called with an empty collection of unavailable components"),
@@ -75,15 +65,6 @@ fn components_missing_msg(cs: &[Component], manifest: &ManifestV2, toolchain: &s
                 c.description(manifest),
                 toolchain,
             );
-
-            if toolchain.starts_with("nightly") {
-                let _ = write!(buf, "{nightly_tips}");
-            }
-
-            let _ = write!(
-                buf,
-                "If you don't need the component, you could try a minimal installation with:\n\n{suggestion}\n\n{TOOLSTATE_MSG}"
-            );
         }
         cs => {
             let cs_str = cs
@@ -93,18 +74,48 @@ fn components_missing_msg(cs: &[Component], manifest: &ManifestV2, toolchain: &s
                 .join(", ");
             let _ = write!(
                 buf,
-                "some components unavailable for download for channel '{toolchain}': {cs_str}"
+                "some components are unavailable for download for channel '{toolchain}': {cs_str}"
             );
+        }
+    }
 
-            if toolchain.starts_with("nightly") {
-                let _ = write!(buf, "{nightly_tips}");
-            }
+    if toolchain.starts_with("nightly") {
+        let _ = write!(
+            buf,
+            "\
+Sometimes not all components are available in any given nightly.
+If you don't need these components, you could try a minimal installation with:
 
-            let _ = write!(
-                buf,
-                "If you don't need the components, you could try a minimal installation with:\n\n{suggestion}\n\n{TOOLSTATE_MSG}"
-            );
-        }
+    rustup toolchain add {toolchain} --profile minimal
+
+If you require these components, please install and use the latest successfully built version,
+which you can find at <https://rust-lang.github.io/rustup-components-history>.
+
+After determining the correct date, install it with a command such as:
+
+    rustup toolchain install nightly-2018-12-27
+
+Then you can use the toolchain with commands such as:
+
+    cargo +nightly-2018-12-27 build"
+        );
+    } else if ["beta", "stable"].iter().any(|&p| toolchain.starts_with(p)) {
+        let _ = write!(
+            buf,
+            "\
+One or many components listed above might have been permanently removed from newer versions
+of the official Rust distribution due to deprecation.
+
+You can find the list of removed components at
+<https://rust-lang.github.io/rustup/devel/concepts/components.html#previous-components>.
+
+If you are updating an existing toolchain, after determining the deprecated component(s)
+in question, please remove them with a command such as:
+
+    rustup component remove --toolchain {toolchain} <COMPONENT>...
+
+After that, you should be able to continue with the update as usual.",
+        );
     }
 
     String::from_utf8(buf).unwrap()
diff --git a/src/errors.rs b/src/errors.rs
index 035ef7fea6..0d13334839 100644
--- a/src/errors.rs
+++ b/src/errors.rs
@@ -148,7 +148,7 @@ fn suggest_message(suggestion: &Option<String>) -> String {
 
 /// Returns a error message indicating that certain [`Component`]s are unavailable.
 ///
-/// See also [`component_missing_msg`](../dist/dist/fn.components_missing_msg.html)
+/// See also [`components_missing_msg`](../dist/dist/fn.components_missing_msg.html)
 /// which generates error messages for component unavailability toolchain-wide operations.
 ///
 /// # Panics
@@ -192,7 +192,7 @@ fn component_unavailable_msg(cs: &[Component], manifest: &Manifest, toolchain: &
 
             let _ = write!(
                 buf,
-                "some components unavailable for download for channel '{toolchain}': {cs_str}"
+                "some components are unavailable for download for channel '{toolchain}': {cs_str}"
             );
 
             if toolchain.starts_with("nightly") {
diff --git a/src/test/mock/clitools.rs b/src/test/mock/clitools.rs
index 1b2ed29859..d81eb0374b 100644
--- a/src/test/mock/clitools.rs
+++ b/src/test/mock/clitools.rs
@@ -93,7 +93,9 @@ pub enum Scenario {
     Unavailable,
     /// Two dates, v2 manifests, RLS unavailable in first date, restored on second.
     UnavailableRls,
-    /// Three dates, v2 manifests, RLS available in first and last, not middle
+    /// Two dates, v2 manifests, RLS available in first stable, removed on second.
+    RemovedRls,
+    /// Three dates, v2 manifests, RLS available in first and second, not last
     MissingComponent,
     /// Three dates, v2 manifests, RLS available in first, middle missing nightly
     MissingNightly,
@@ -152,6 +154,7 @@ impl ConstState {
                 Scenario::MissingNightly => RwLock::new(None),
                 Scenario::MultiHost => RwLock::new(None),
                 Scenario::None => RwLock::new(None),
+                Scenario::RemovedRls => RwLock::new(None),
                 Scenario::SimpleV1 => RwLock::new(None),
                 Scenario::SimpleV2 => RwLock::new(None),
                 Scenario::Unavailable => RwLock::new(None),
@@ -1152,6 +1155,10 @@ fn create_mock_dist_server(path: &Path, s: Scenario) {
                 Release::stable("1.1.0", "2015-01-02"),
             ]
         }
+        Scenario::RemovedRls => vec![
+            Release::stable("1.78.0", "2024-05-01"),
+            Release::stable("1.79.0", "2024-06-15").with_rls(RlsStatus::Unavailable),
+        ],
         Scenario::SimpleV1 | Scenario::SimpleV2 => vec![
             Release::new("nightly", "1.3.0", "2015-01-02", "2").with_rls(RlsStatus::Renamed),
             Release::beta("1.2.0", "2015-01-02"),
@@ -1199,6 +1206,7 @@ fn create_mock_dist_server(path: &Path, s: Scenario) {
         | Scenario::MultiHost
         | Scenario::Unavailable
         | Scenario::UnavailableRls
+        | Scenario::RemovedRls
         | Scenario::MissingNightly
         | Scenario::HostGoesMissingBefore
         | Scenario::HostGoesMissingAfter
diff --git a/tests/suite/cli_v2.rs b/tests/suite/cli_v2.rs
index 995094d298..7d678fd790 100644
--- a/tests/suite/cli_v2.rs
+++ b/tests/suite/cli_v2.rs
@@ -1359,11 +1359,12 @@ async fn add_missing_component_toolchain() {
         &["rustup", "toolchain", "add", "nightly"],
         for_host!(
             r"component 'rust-std' for target '{0}' is unavailable for download for channel 'nightly'
-Sometimes not all components are available in any given nightly. If you don't need the component, you could try a minimal installation with:
+Sometimes not all components are available in any given nightly.
+If you don't need these components, you could try a minimal installation with:
 
     rustup toolchain add nightly --profile minimal
 
-If you require these components, please install and use the latest successful build version,
+If you require these components, please install and use the latest successfully built version,
 which you can find at <https://rust-lang.github.io/rustup-components-history>.
 
 After determining the correct date, install it with a command such as:
@@ -1377,6 +1378,43 @@ Then you can use the toolchain with commands such as:
     ).await;
 }
 
+#[tokio::test]
+async fn update_removed_component_toolchain() {
+    let mut cx = CliTestContext::new(Scenario::RemovedRls).await;
+    set_current_dist_date(&cx.config, "2024-05-01");
+    cx.config.expect_ok(&["rustup", "default", "stable"]).await;
+
+    // Install `rls` on the first day.
+    cx.config
+        .expect_stdout_ok(&["rustc", "--version"], "1.78.0")
+        .await;
+    cx.config
+        .expect_ok(&["rustup", "component", "add", "rls"])
+        .await;
+    cx.config.expect_component_executable("rls").await;
+
+    // `rls` is missing on the second day.
+    set_current_dist_date(&cx.config, "2024-06-15");
+
+    // An update at this time should inform the user of an unavailable component.
+    cx.config
+        .expect_err(
+            &["rustup", "update", "stable"],
+            for_host!(
+                r"component 'rls' for target '{0}' is unavailable for download for channel 'stable'
+One or many components listed above might have been permanently removed from newer versions
+of the official Rust distribution due to deprecation."
+            ),
+        )
+        .await;
+
+    // We're still stuck with the old version.
+    cx.config
+        .expect_stdout_ok(&["rustc", "--version"], "1.78.0")
+        .await;
+    cx.config.expect_component_executable("rls").await;
+}
+
 #[tokio::test]
 async fn update_unavailable_force() {
     let mut cx = CliTestContext::new(Scenario::SimpleV2).await;