diff --git a/meta/lib/oeqa/selftest/cases/devtool.py b/meta/lib/oeqa/selftest/cases/devtool.py
index 7145755fed..d84a18e8b6 100644
--- a/meta/lib/oeqa/selftest/cases/devtool.py
+++ b/meta/lib/oeqa/selftest/cases/devtool.py
@@ -4175,8 +4175,6 @@ class DevtoolIdeSdkTests(DevtoolBase):
         (see _lldb_debug_cpp_example_batch_commands), and checks that the
         expected magic string and variable values are visible.
         """
-        sshargs = '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'
-
         with open(os.path.join(tempdir, '.vscode', 'launch.json')) as f:
             launch_d = json.load(f)
         with open(os.path.join(tempdir, '.vscode', 'tasks.json')) as f:
@@ -4208,7 +4206,9 @@ class DevtoolIdeSdkTests(DevtoolBase):
             # to SSH via subprocess without an intermediate shell.
             ssh_cmd[-1] = ssh_cmd[-1][1:-1].replace('\\$', '$')
 
-        # Extract connection details from initCommands
+        # The generated foreground preLaunchTask does not complete until its
+        # target-side command has observed lldb-server listening.  Run it
+        # synchronously so this selftest follows the same ordering as VS Code.
         init_commands = lldb_config["initCommands"]
         connect_cmd = next((c for c in init_commands if "platform connect" in c), None)
         self.assertIsNotNone(connect_cmd, "initCommands should contain a platform connect command")
@@ -4218,47 +4218,41 @@ class DevtoolIdeSdkTests(DevtoolBase):
         lldb_binary = os.path.join(lldb_native_sysroot, 'usr', 'bin', 'lldb')
         self.assertExists(lldb_binary, "lldb binary should exist in lldb-native sysroot")
 
-        with RunCmdBackground(ssh_cmd, output_log=self._cmd_logger):
-            time.sleep(1)
+        self.logger.debug("Starting lldb-server via SSH: %s", " ".join(ssh_cmd))
+        runCmd(ssh_cmd, output_log=self._cmd_logger)
 
-            # Verify lldb-server is running on the target
-            r = runCmd('ssh %s root@%s ps' % (sshargs, qemu.ip),
-                       output_log=self._cmd_logger)
-            self.assertIn("lldb-server", r.output,
-                          "lldb-server should be running on target")
+        # Run lldb --batch: connect to platform, create target with remote-file,
+        # set a source-level breakpoint, and run.
+        # targetCreateCommands replaces the "program" field; each entry is
+        # passed as a separate -o command in batch mode.
+        target_create_commands = lldb_config.get("targetCreateCommands", [])
+        source_map = lldb_config.get("sourceMap", {})
 
-            # Run lldb --batch: connect to platform, create target with remote-file,
-            # set a source-level breakpoint, and run.
-            # targetCreateCommands replaces the "program" field; each entry is
-            # passed as a separate -o command in batch mode.
-            target_create_commands = lldb_config.get("targetCreateCommands", [])
-            source_map = lldb_config.get("sourceMap", {})
-
-            lldb_batch = [lldb_binary, "--batch"]
-            for cmd in init_commands:
-                lldb_batch += ["-o", cmd]
-            for cmd in target_create_commands:
-                lldb_batch += ["-o", cmd]
-            if source_map:
-                # "settings set target.source-map" replaces the *entire*
-                # mapping list rather than appending to it. Issuing one
-                # "-o settings set target.source-map ..." per entry (as done
-                # previously) silently discards all but the last mapping, so
-                # LLDB ends up resolving source files (and verifying their
-                # DWARF MD5 checksum) against the wrong location, e.g. a
-                # stale rootfs-dbg copy of a devtool-modified recipe's own
-                # sources instead of the freshly edited workspace srctree.
-                # All pairs must therefore be set together in a single
-                # command, exactly like CodeLLDB itself does.
-                source_map_args = []
-                for k, v in source_map.items():
-                    v_resolved = v.replace("${workspaceFolder}", tempdir)
-                    source_map_args += [k, v_resolved]
-                lldb_batch += ["-o", "settings set target.source-map %s" % " ".join(source_map_args)]
-            lldb_batch += self._lldb_debug_cpp_example_batch_commands(tempdir)
-            r = runCmd(lldb_batch, output_log=self._cmd_logger)
-            self.assertEqual(r.status, 0, "lldb batch session failed: %s" % r.output)
-            self._lldb_debug_cpp_example_check(r.output, magic_string)
+        lldb_batch = [lldb_binary, "--batch"]
+        for cmd in init_commands:
+            lldb_batch += ["-o", cmd]
+        for cmd in target_create_commands:
+            lldb_batch += ["-o", cmd]
+        if source_map:
+            # "settings set target.source-map" replaces the *entire*
+            # mapping list rather than appending to it. Issuing one
+            # "-o settings set target.source-map ..." per entry (as done
+            # previously) silently discards all but the last mapping, so
+            # LLDB ends up resolving source files (and verifying their
+            # DWARF MD5 checksum) against the wrong location, e.g. a
+            # stale rootfs-dbg copy of a devtool-modified recipe's own
+            # sources instead of the freshly edited workspace srctree.
+            # All pairs must therefore be set together in a single
+            # command, exactly like CodeLLDB itself does.
+            source_map_args = []
+            for k, v in source_map.items():
+                v_resolved = v.replace("${workspaceFolder}", tempdir)
+                source_map_args += [k, v_resolved]
+            lldb_batch += ["-o", "settings set target.source-map %s" % " ".join(source_map_args)]
+        lldb_batch += self._lldb_debug_cpp_example_batch_commands(tempdir)
+        r = runCmd(lldb_batch, output_log=self._cmd_logger)
+        self.assertEqual(r.status, 0, "lldb batch session failed: %s" % r.output)
+        self._lldb_debug_cpp_example_check(r.output, magic_string)
 
     @OETestTag("runqemu")
     def test_devtool_ide_sdk_code_cmake_clang(self):
