diff --git a/tests/qtest/migration-helpers.c b/tests/qtest/migration-helpers.c
index 0025933883..16e940d910 100644
--- a/tests/qtest/migration-helpers.c
+++ b/tests/qtest/migration-helpers.c
@@ -528,3 +528,11 @@ void migration_event_wait(QTestState *s, const char *target)
         qobject_unref(response);
     } while (!found);
 }
+
+char *migrate_get_unique_serial(const char *tmpfs)
+{
+    static int i;
+
+    assert(i < INT_MAX);
+    return g_strdup_printf("%s/serial_%d", tmpfs, i++);
+}
diff --git a/tests/qtest/migration-helpers.h b/tests/qtest/migration-helpers.h
index 72dba369fb..c7a36a33d6 100644
--- a/tests/qtest/migration-helpers.h
+++ b/tests/qtest/migration-helpers.h
@@ -20,6 +20,7 @@ typedef struct QTestMigrationState {
     bool resume_seen;
     bool suspend_seen;
     bool suspend_me;
+    char *serial;
 } QTestMigrationState;
 
 bool migrate_watch_for_events(QTestState *who, const char *name,
@@ -64,5 +65,6 @@ static inline bool probe_o_direct_support(const char *tmpfs)
 #endif
 void migration_test_add(const char *path, void (*fn)(void));
 void migration_event_wait(QTestState *s, const char *target);
+char *migrate_get_unique_serial(const char *tmpfs);
 
 #endif /* MIGRATION_HELPERS_H */
diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c
index d56894dd97..f8919a083b 100644
--- a/tests/qtest/migration-test.c
+++ b/tests/qtest/migration-test.c
@@ -192,9 +192,8 @@ static void bootfile_create(char *dir, bool suspend_me)
  * we get an 'A' followed by an endless string of 'B's
  * but on the destination we won't have the A (unless we enabled suspend/resume)
  */
-static void wait_for_serial(const char *side)
+static void wait_for_serial(const char *serialpath)
 {
-    g_autofree char *serialpath = g_strdup_printf("%s/%s", tmpfs, side);
     FILE *serialfile = fopen(serialpath, "r");
 
     do {
@@ -216,7 +215,7 @@ static void wait_for_serial(const char *side)
             break;
 
         default:
-            fprintf(stderr, "Unexpected %d on %s serial\n", readvalue, side);
+            fprintf(stderr, "Unexpected %d on %s\n", readvalue, serialpath);
             g_assert_not_reached();
         }
     } while (true);
@@ -818,16 +817,17 @@ static int test_migrate_start(QTestState **from, QTestState **to,
 
         src_state = (QTestMigrationState) { };
         src_state.suspend_me = args->suspend_me;
+        src_state.serial = migrate_get_unique_serial(tmpfs);
 
         cmd_source = g_strdup_printf("-accel kvm%s -accel tcg "
                                      "-machine %s,%s "
                                      "-name source,debug-threads=on "
                                      "-m %s "
-                                     "-serial file:%s/src_serial "
+                                     "-serial file:%s "
                                      "%s %s %s %s %s",
                                      kvm_opts ? kvm_opts : "",
                                      machine, machine_opts,
-                                     memory_size, tmpfs,
+                                     memory_size, src_state.serial,
                                      arch_opts ? arch_opts : "",
                                      arch_source ? arch_source : "",
                                      shmem_opts ? shmem_opts : "",
@@ -841,17 +841,18 @@ static int test_migrate_start(QTestState **from, QTestState **to,
     }
 
     dst_state = (QTestMigrationState) { };
+    dst_state.serial = migrate_get_unique_serial(tmpfs);
 
     cmd_target = g_strdup_printf("-accel kvm%s -accel tcg "
                                  "-machine %s,%s "
                                  "-name target,debug-threads=on "
                                  "-m %s "
-                                 "-serial file:%s/dest_serial "
+                                 "-serial file:%s "
                                  "-incoming %s "
                                  "%s %s %s %s %s",
                                  kvm_opts ? kvm_opts : "",
                                  machine, machine_opts,
-                                 memory_size, tmpfs, uri,
+                                 memory_size, dst_state.serial, uri,
                                  arch_opts ? arch_opts : "",
                                  arch_target ? arch_target : "",
                                  shmem_opts ? shmem_opts : "",
@@ -911,8 +912,10 @@ static void test_migrate_end(QTestState *from, QTestState *to, bool test_dest)
     qtest_quit(to);
 
     cleanup("migsocket");
-    cleanup("src_serial");
-    cleanup("dest_serial");
+    unlink(src_state.serial);
+    g_free(src_state.serial);
+    unlink(dst_state.serial);
+    g_free(dst_state.serial);
     cleanup(FILE_TEST_FILENAME);
 }
 
@@ -1290,7 +1293,7 @@ static int migrate_postcopy_prepare(QTestState **from_ptr,
                              "                'port': '0' } } ] } }");
 
     /* Wait for the first serial output from the source */
-    wait_for_serial("src_serial");
+    wait_for_serial(src_state.serial);
     wait_for_suspend(from, &src_state);
 
     migrate_qmp(from, to, NULL, NULL, "{}");
@@ -1314,7 +1317,7 @@ static void migrate_postcopy_complete(QTestState *from, QTestState *to,
     }
 
     /* Make sure we get at least one "B" on destination */
-    wait_for_serial("dest_serial");
+    wait_for_serial(dst_state.serial);
 
     if (uffd_feature_thread_id) {
         read_blocktime(to);
@@ -1717,7 +1720,7 @@ static void test_precopy_common(MigrateCommon *args)
 
     /* Wait for the first serial output from the source */
     if (args->result == MIG_TEST_SUCCEED) {
-        wait_for_serial("src_serial");
+        wait_for_serial(src_state.serial);
         wait_for_suspend(from, &src_state);
     }
 
@@ -1794,7 +1797,7 @@ static void test_precopy_common(MigrateCommon *args)
             qtest_qmp_assert_success(to, "{'execute': 'system_wakeup'}");
         }
 
-        wait_for_serial("dest_serial");
+        wait_for_serial(dst_state.serial);
     }
 
 finish:
@@ -1869,7 +1872,7 @@ static void test_file_common(MigrateCommon *args, bool stop_src)
     }
 
     migrate_ensure_converge(from);
-    wait_for_serial("src_serial");
+    wait_for_serial(src_state.serial);
 
     if (stop_src) {
         qtest_qmp_assert_success(from, "{ 'execute' : 'stop'}");
@@ -1896,7 +1899,7 @@ static void test_file_common(MigrateCommon *args, bool stop_src)
     }
     wait_for_resume(to, &dst_state);
 
-    wait_for_serial("dest_serial");
+    wait_for_serial(dst_state.serial);
 
     if (check_offset) {
         file_check_offset_region();
@@ -2039,7 +2042,7 @@ static void test_ignore_shared(void)
     migrate_set_capability(to, "x-ignore-shared", true);
 
     /* Wait for the first serial output from the source */
-    wait_for_serial("src_serial");
+    wait_for_serial(src_state.serial);
 
     migrate_qmp(from, to, uri, NULL, "{}");
 
@@ -2049,7 +2052,7 @@ static void test_ignore_shared(void)
 
     qtest_qmp_eventwait(to, "RESUME");
 
-    wait_for_serial("dest_serial");
+    wait_for_serial(dst_state.serial);
     wait_for_migration_complete(from);
 
     /* Check whether shared RAM has been really skipped */
@@ -2665,7 +2668,7 @@ static void do_test_validate_uuid(MigrateStart *args, bool should_fail)
     migrate_set_capability(from, "validate-uuid", true);
 
     /* Wait for the first serial output from the source */
-    wait_for_serial("src_serial");
+    wait_for_serial(src_state.serial);
 
     migrate_qmp(from, to, uri, NULL, "{}");
 
@@ -2729,7 +2732,7 @@ static void do_test_validate_uri_channel(MigrateCommon *args)
     }
 
     /* Wait for the first serial output from the source */
-    wait_for_serial("src_serial");
+    wait_for_serial(src_state.serial);
 
     /*
      * 'uri' and 'channels' validation is checked even before the migration
@@ -2819,7 +2822,7 @@ static void test_migrate_auto_converge(void)
     migrate_set_capability(from, "pause-before-switchover", true);
 
     /* Wait for the first serial output from the source */
-    wait_for_serial("src_serial");
+    wait_for_serial(src_state.serial);
 
     migrate_qmp(from, to, uri, NULL, "{}");
 
@@ -2881,7 +2884,7 @@ static void test_migrate_auto_converge(void)
 
     qtest_qmp_eventwait(to, "RESUME");
 
-    wait_for_serial("dest_serial");
+    wait_for_serial(dst_state.serial);
     wait_for_migration_complete(from);
 
     test_migrate_end(from, to, true);
@@ -3292,7 +3295,7 @@ static void test_multifd_tcp_cancel(void)
     migrate_incoming_qmp(to, "tcp:127.0.0.1:0", "{}");
 
     /* Wait for the first serial output from the source */
-    wait_for_serial("src_serial");
+    wait_for_serial(src_state.serial);
 
     migrate_qmp(from, to, NULL, NULL, "{}");
 
@@ -3303,7 +3306,8 @@ static void test_multifd_tcp_cancel(void)
     /* Make sure QEMU process "to" exited */
     qtest_set_expected_status(to, EXIT_FAILURE);
     qtest_wait_qemu(to);
-    qtest_quit(to);
+    unlink(dst_state.serial);
+    g_free(dst_state.serial);
 
     /*
      * Ensure the source QEMU finishes its cancellation process before we
@@ -3341,7 +3345,7 @@ static void test_multifd_tcp_cancel(void)
     wait_for_stop(from, &src_state);
     qtest_qmp_eventwait(to2, "RESUME");
 
-    wait_for_serial("dest_serial");
+    wait_for_serial(dst_state.serial);
     wait_for_migration_complete(from);
     test_migrate_end(from, to2, true);
 }
@@ -3484,13 +3488,16 @@ static QTestState *dirtylimit_start_vm(void)
     QTestState *vm = NULL;
     g_autofree gchar *cmd = NULL;
 
+    src_state = (QTestMigrationState) { };
+    src_state.serial = migrate_get_unique_serial(tmpfs);
+
     bootfile_create(tmpfs, false);
     cmd = g_strdup_printf("-accel kvm,dirty-ring-size=4096 "
                           "-name dirtylimit-test,debug-threads=on "
                           "-m 150M -smp 1 "
-                          "-serial file:%s/vm_serial "
+                          "-serial file:%s "
                           "-drive file=%s,format=raw ",
-                          tmpfs, bootpath);
+                          src_state.serial, bootpath);
 
     vm = qtest_init(cmd);
     return vm;
@@ -3499,7 +3506,8 @@ static QTestState *dirtylimit_start_vm(void)
 static void dirtylimit_stop_vm(QTestState *vm)
 {
     qtest_quit(vm);
-    cleanup("vm_serial");
+    unlink(src_state.serial);
+    g_free(src_state.serial);
 }
 
 static void test_vcpu_dirty_limit(void)
@@ -3515,7 +3523,7 @@ static void test_vcpu_dirty_limit(void)
     vm = dirtylimit_start_vm();
 
     /* Wait for the first serial output from the vm*/
-    wait_for_serial("vm_serial");
+    wait_for_serial(src_state.serial);
 
     /* Do dirtyrate measurement with calc time equals 1s */
     calc_dirty_rate(vm, 1);
@@ -3608,7 +3616,7 @@ static void migrate_dirty_limit_wait_showup(QTestState *from,
     migrate_set_capability(from, "pause-before-switchover", true);
 
     /* Wait for the serial output from the source */
-    wait_for_serial("src_serial");
+    wait_for_serial(src_state.serial);
 }
 
 /*
@@ -3744,7 +3752,7 @@ static void test_migrate_dirty_limit(void)
 
     qtest_qmp_eventwait(to, "RESUME");
 
-    wait_for_serial("dest_serial");
+    wait_for_serial(dst_state.serial);
     wait_for_migration_complete(from);
 
     test_migrate_end(from, to, true);
