diff --git a/scripts/runqemu b/scripts/runqemu
index c9f6481cd11e..967a86b78304 100755
--- a/scripts/runqemu
+++ b/scripts/runqemu
@@ -227,8 +227,6 @@ class BaseConfig(object):
         # pid of the actual qemu process
         self.qemu_environ = os.environ.copy()
         self.qemuprocess = None
-        # avoid cleanup twice
-        self.cleaned = False
         # Files to cleanup after run
         self.cleanup_files = []
         self.qmp = None
@@ -1658,6 +1656,7 @@ to your build configuration.
         process = subprocess.Popen(cmds, stderr=subprocess.PIPE, pass_fds=pass_fds, env=self.qemu_environ)
         self.qemuprocess = process
         retcode = process.wait()
+        signal.alarm(0)
         if retcode:
             if retcode == -signal.SIGTERM:
                 logger.info("Qemu terminated by SIGTERM")
@@ -1672,22 +1671,11 @@ to your build configuration.
                 raise RunQemuError('Failed to run %s' % str(cmd))
 
     def cleanup(self):
-        if self.cleaned:
-            return
-
         # avoid dealing with SIGTERM when cleanup function is running
         signal.signal(signal.SIGTERM, signal.SIG_IGN)
 
         logger.info("Cleaning up")
 
-        if self.qemuprocess:
-            try:
-                # give it some time to shut down, ignore return values and output
-                self.qemuprocess.send_signal(signal.SIGTERM)
-                self.qemuprocess.communicate(timeout=5)
-            except subprocess.TimeoutExpired:
-                self.qemuprocess.kill()
-
         with open('/proc/uptime', 'r') as f:
             uptime_seconds = f.readline().split()[0]
         logger.info('Host uptime: %s\n' % uptime_seconds)
@@ -1718,8 +1706,6 @@ to your build configuration.
         # Deliberately ignore the return code of 'tput smam'.
         subprocess.call(["tput", "smam"])
 
-        self.cleaned = True
-
     def run_bitbake_env(self, mach=None, target=''):
 
         if not mach:
@@ -1806,9 +1792,26 @@ def main():
 
         def sigterm_handler(signum, frame):
             logger.info("Received signal: %s" % (signum))
-            config.cleanup()
+            # Stop qemu: process.wait() in start_qemu() will reap it. Add an
+            # alarm to send a SIGKILL if QEMU is still alive 5s later.
+            if config.qemuprocess is not None and config.qemuprocess.returncode is None:
+                try:
+                    config.qemuprocess.terminate()
+                except OSError:
+                    pass
+                signal.alarm(5)
         signal.signal(signal.SIGTERM, sigterm_handler)
 
+        def sigalrm_handler(signum, frame):
+            # Force-kill qemu if it is still running after the grace period.
+            # No-op once qemu has been reaped (returncode set).
+            if config.qemuprocess is not None and config.qemuprocess.returncode is None:
+                try:
+                    config.qemuprocess.kill()
+                except OSError:
+                    pass
+        signal.signal(signal.SIGALRM, sigalrm_handler)
+
         config.check_args()
         config.read_qemuboot()
         config.check_and_set()
