diff --git a/UnitTest1/unittest1.cpp b/UnitTest1/unittest1.cpp
index 8f7ccb4d03c5b95ae5313df8573c0b6e9a2c0642..7683df877effa851f1f2f9df9fe143e82b58e498 100644
--- a/UnitTest1/unittest1.cpp
+++ b/UnitTest1/unittest1.cpp
@@ -619,6 +619,14 @@ namespace UnitTest1
             Assert::AreEqual(ret, 0);
         }
 
+        TEST_METHOD(test_transmit_cnxid)
+        {
+            int ret = transmit_cnxid_test();
+
+            Assert::AreEqual(ret, 0);
+        }
+
+
         TEST_METHOD(stress)
         {
             int ret = stress_test();
diff --git a/picoquic/picoquic_internal.h b/picoquic/picoquic_internal.h
index 845cbd22d1bee7f1d38586e494d27cf4f4f88b6e..85d0f05f6ef672b8c57cf3c2304fb6601ad2a5ae 100644
--- a/picoquic/picoquic_internal.h
+++ b/picoquic/picoquic_internal.h
@@ -39,6 +39,7 @@ extern "C" {
 #define PICOQUIC_PRACTICAL_MAX_MTU 1440
 #define PICOQUIC_RETRY_SECRET_SIZE 64
 #define PICOQUIC_DEFAULT_0RTT_WINDOW 4096
+#define PICOQUIC_NB_PATH_TARGET 4
 
 #define PICOQUIC_NUMBER_OF_EPOCHS 4
 #define PICOQUIC_NUMBER_OF_EPOCH_OFFSETS (PICOQUIC_NUMBER_OF_EPOCHS+1)
diff --git a/picoquic/sender.c b/picoquic/sender.c
index 241a1299d5684be89f0192700d5f405f6d2380ed..d60a6341c7a7effe380c4de890679f4dad4cafde 100644
--- a/picoquic/sender.c
+++ b/picoquic/sender.c
@@ -1187,6 +1187,13 @@ void picoquic_cnx_set_next_wake_time(picoquic_cnx_t* cnx, uint64_t current_time)
     else if (path_x->cwin > path_x->bytes_in_transit && picoquic_is_mtu_probe_needed(cnx, path_x)) {
         blocked = 0;
     }
+    else if ((cnx->cnx_state == picoquic_state_client_ready ||
+        cnx->cnx_state == picoquic_state_server_ready) &&
+        cnx->remote_parameters.migration_disabled == 0 &&
+        cnx->local_parameters.migration_disabled == 0 &&
+        cnx->nb_paths < PICOQUIC_NB_PATH_TARGET) {
+        blocked = 0;
+    }
     else {
         for (picoquic_packet_context_enum pc = 0; pc < picoquic_nb_packet_context; pc++) {
             picoquic_packet_t* p = cnx->pkt_ctx[pc].retransmit_oldest;
@@ -2010,6 +2017,28 @@ int picoquic_prepare_packet_closing(picoquic_cnx_t* cnx, picoquic_path_t * path_
     return ret;
 }
 
+/* Create a new path, register it, and file the corresponding connection ID frame */
+int picoquic_prepare_new_path_and_id(picoquic_cnx_t* cnx, uint8_t* bytes, size_t bytes_max, int64_t current_time, size_t* consumed)
+{
+    int ret = 0;
+    int path_index;
+
+    path_index = picoquic_create_path(cnx, current_time, NULL, NULL);
+
+    picoquic_register_path(cnx, cnx->path[path_index]);
+
+    ret = picoquic_prepare_connection_id_frame(cnx, cnx->path[path_index], bytes, bytes_max, consumed);
+
+    if (ret == PICOQUIC_ERROR_FRAME_BUFFER_TOO_SMALL) {
+        /* Oops. Try again next time. */
+        picoquic_delete_path(cnx, path_index);
+        *consumed = 0;
+    }
+
+    return ret;
+}
+
+
 /*  Prepare the next packet to send when in one the ready states */
 int picoquic_prepare_packet_ready(picoquic_cnx_t* cnx, picoquic_path_t * path_x, picoquic_packet_t* packet,
     uint64_t current_time, uint8_t* send_buffer, size_t send_buffer_max, size_t* send_length)
@@ -2147,6 +2176,25 @@ int picoquic_prepare_packet_ready(picoquic_cnx_t* cnx, picoquic_path_t * path_x,
                                 break;
                             }
                         }
+
+                        /* If there are not enough paths, create and advertise */
+                        while (ret == 0 && cnx->remote_parameters.migration_disabled == 0 &&
+                            cnx->local_parameters.migration_disabled == 0 &&
+                            cnx->nb_paths < PICOQUIC_NB_PATH_TARGET) {
+                            ret = picoquic_prepare_new_path_and_id(cnx, &bytes[length],
+                                send_buffer_min_max - checksum_overhead - length,
+                                current_time, &data_bytes);
+                            if (ret == 0) {
+                                length += (uint32_t)data_bytes;
+                            }
+                            else {
+                                if (ret == PICOQUIC_ERROR_FRAME_BUFFER_TOO_SMALL) {
+                                    ret = 0;
+                                }
+                                break;
+                            }
+                        }
+
                         /* If necessary, encode the max data frame */
                         if (ret == 0 && 2 * cnx->data_received > cnx->maxdata_local) {
                             ret = picoquic_prepare_max_data_frame(cnx, 2 * cnx->data_received, &bytes[length],
diff --git a/picoquic_t/picoquic_t.c b/picoquic_t/picoquic_t.c
index fe0343b46ffeff9446aa6f4fa2c69730cd83e898..e2e3cf66437662d5e73e23e54f39366dd63836dd 100644
--- a/picoquic_t/picoquic_t.c
+++ b/picoquic_t/picoquic_t.c
@@ -130,7 +130,8 @@ static const picoquic_test_def_t test_table[] = {
     { "zero_rtt_retry", zero_rtt_retry_test },
     { "random_tester", random_tester_test},
     { "stress", stress_test },
-    { "fuzz", fuzz_test }
+    { "fuzz", fuzz_test },
+    { "transmit_cnxid", transmit_cnxid_test }
 };
 
 static size_t const nb_tests = sizeof(test_table) / sizeof(picoquic_test_def_t);
diff --git a/picoquictest/picoquictest.h b/picoquictest/picoquictest.h
index 6326f19a6adf96d4f408c607a6b5547571c76d3a..35ed2cc675a386d6f45a1a702cc766f581b0c457 100644
--- a/picoquictest/picoquictest.h
+++ b/picoquictest/picoquictest.h
@@ -123,6 +123,7 @@ int fuzz_test();
 int random_tester_test();
 int cnxid_stash_test();
 int new_cnxid_test();
+int transmit_cnxid_test();
 
 #ifdef __cplusplus
 }
diff --git a/picoquictest/tls_api_test.c b/picoquictest/tls_api_test.c
index 30b3d3e3d2d9a45141b2ca297480afa0a9f96510..d21e97df0de063e6281ef4047763fea8e0d07ef9 100644
--- a/picoquictest/tls_api_test.c
+++ b/picoquictest/tls_api_test.c
@@ -1259,7 +1259,7 @@ int tls_api_one_scenario_test(test_api_stream_desc_t* scenario,
 
 int tls_api_oneway_stream_test()
 {
-    return tls_api_one_scenario_test(test_scenario_oneway, sizeof(test_scenario_oneway), 0, 0, 0, 0, 65000, NULL);
+    return tls_api_one_scenario_test(test_scenario_oneway, sizeof(test_scenario_oneway), 0, 0, 0, 0, 70000, NULL);
 }
 
 int tls_api_q_and_r_stream_test()
@@ -1269,7 +1269,7 @@ int tls_api_q_and_r_stream_test()
 
 int tls_api_q2_and_r2_stream_test()
 {
-    return tls_api_one_scenario_test(test_scenario_q2_and_r2, sizeof(test_scenario_q2_and_r2), 0, 0, 0, 0, 75000, NULL);
+    return tls_api_one_scenario_test(test_scenario_q2_and_r2, sizeof(test_scenario_q2_and_r2), 0, 0, 0, 0, 80000, NULL);
 }
 
 int tls_api_very_long_stream_test()
@@ -3453,5 +3453,110 @@ int client_error_test()
         test_ctx = NULL;
     }
 
+    return ret;
+}
+
+/*
+ * Set a connection, then verify that the "new connection id" frames have been exchanged properly.
+ * Use the "check stash" function to verify that new connection ID were properly
+ * stashed on each side.
+ *
+ * TODO: also test that no New Connection Id frames are sent if migration is disabled 
+ */
+
+int transmit_cnxid_test_stash(picoquic_cnx_t * cnx1, picoquic_cnx_t * cnx2, char const * cnx_text)
+{
+    int ret = 0;
+    picoquic_cnxid_stash_t * stash = cnx1->cnxid_stash_first;
+    int path_id = 1;
+
+    while (stash != NULL && path_id < cnx2->nb_paths) {
+        if (picoquic_compare_connection_id(&stash->cnx_id, &cnx2->path[path_id]->local_cnxid) != 0) {
+            DBG_PRINTF("On %s, cnx ID of stash #%d does not match path[%d] of peer.\n",
+                cnx_text, path_id - 1, path_id);
+            ret = -1;
+            break;
+        }
+        stash = stash->next_in_stash;
+        path_id++;
+    }
+
+    if (ret == 0 && path_id < cnx2->nb_paths) {
+        DBG_PRINTF("On %s, %d items in stash instead instead of %d.\n", cnx_text, path_id - 1, cnx2->nb_paths);
+        ret = -1;
+    }
+
+    if (ret == 0 && stash != NULL) {
+        DBG_PRINTF("On %s, more than %d items in stash.\n", cnx_text, path_id - 1);
+        ret = -1;
+    }
+
+    return ret;
+
+}
+
+int transmit_cnxid_test()
+{
+    uint64_t simulated_time = 0;
+    uint64_t next_time = 0;
+    uint64_t loss_mask = 0;
+    picoquic_test_tls_api_ctx_t* test_ctx = NULL;
+    int ret = tls_api_init_ctx(&test_ctx, PICOQUIC_INTERNAL_TEST_VERSION_1,
+        PICOQUIC_TEST_SNI, PICOQUIC_TEST_ALPN, &simulated_time, NULL, 0, 0, 0);
+
+    if (ret == 0) {
+        ret = tls_api_connection_loop(test_ctx, &loss_mask, 0, &simulated_time);
+    }
+
+    /* run a receive loop until no outstanding data */
+    if (ret == 0) {
+        uint64_t time_out = simulated_time + 4000000;
+        int nb_rounds = 0;
+        int success = 0;
+
+        while (ret == 0 && simulated_time < time_out &&
+            nb_rounds < 2048 && test_ctx->cnx_client->cnx_state != picoquic_state_disconnected) {
+            int was_active = 0;
+
+            ret = tls_api_one_sim_round(test_ctx, &simulated_time, &was_active);
+            nb_rounds++;
+
+            if (test_ctx->cnx_client->nb_paths >= PICOQUIC_NB_PATH_TARGET &&
+                test_ctx->cnx_server->nb_paths >= PICOQUIC_NB_PATH_TARGET &&
+                picoquic_is_cnx_backlog_empty(test_ctx->cnx_client) &&
+                picoquic_is_cnx_backlog_empty(test_ctx->cnx_server)) {
+                success = 1;
+                break;
+            }
+        }
+
+        if (ret == 0 && success == 0) {
+            DBG_PRINTF("Exit synch loop after %d rounds, backlog or not enough paths (%d & %d).\n",
+                nb_rounds, test_ctx->cnx_client->nb_paths, test_ctx->cnx_server->nb_paths);
+        }
+    }
+
+    if (ret == 0) {
+        if (test_ctx->cnx_client->nb_paths < PICOQUIC_NB_PATH_TARGET) {
+            DBG_PRINTF("Only %d paths created on client.\n", test_ctx->cnx_client->nb_paths);
+            ret = -1;
+        } else if (test_ctx->cnx_server->nb_paths < PICOQUIC_NB_PATH_TARGET) {
+            DBG_PRINTF("Only %d paths created on server.\n", test_ctx->cnx_server->nb_paths);
+        }
+    }
+
+    if (ret == 0) {
+        ret = transmit_cnxid_test_stash(test_ctx->cnx_client, test_ctx->cnx_server, "client");
+    }
+
+    if (ret == 0) {
+        ret = transmit_cnxid_test_stash(test_ctx->cnx_server, test_ctx->cnx_client, "server");
+    }
+
+    if (test_ctx != NULL) {
+        tls_api_delete_ctx(test_ctx);
+        test_ctx = NULL;
+    }
+
     return ret;
 }
\ No newline at end of file