diff --git a/picoquic/picoquic.h b/picoquic/picoquic.h
index 9f714493091e5b3c23928b98087d744647efd5d3..a83bb794ae779b95908db81062944bc156ffecb3 100644
--- a/picoquic/picoquic.h
+++ b/picoquic/picoquic.h
@@ -348,6 +348,8 @@ int picoquic_set_verify_certificate_callback(picoquic_quic_t* quic, picoquic_ver
 /* Set client authentication in TLS (if enabled, client is required to send certificates). */
 void picoquic_set_client_authentication(picoquic_quic_t* quic, int client_authentication);
 
+/* Set default padding policy for the context */
+
 /* Connection context creation and registration */
 picoquic_cnx_t* picoquic_create_cnx(picoquic_quic_t* quic,
     picoquic_connection_id_t initial_cnx_id, picoquic_connection_id_t remote_cnx_id,
@@ -380,6 +382,9 @@ picoquic_cnx_t* picoquic_get_earliest_cnx_to_wake(picoquic_quic_t* quic, uint64_
 
 picoquic_state_enum picoquic_get_cnx_state(picoquic_cnx_t* cnx);
 
+void picoquic_cnx_set_padding_policy(picoquic_cnx_t * cnx, uint32_t padding_multiple, uint32_t padding_minsize);
+void picoquic_cnx_get_padding_policy(picoquic_cnx_t * cnx, uint32_t * padding_multiple, uint32_t * padding_minsize);
+
 int picoquic_tls_is_psk_handshake(picoquic_cnx_t* cnx);
 int picoquic_tls_is_early_data_skipped(picoquic_cnx_t* cnx);
 
diff --git a/picoquic/picoquic_internal.h b/picoquic/picoquic_internal.h
index 3d4c0ea8942428d1e25b828dbb32c5c3d7a2d80c..eb6a982c0b152518c6ebdd6499895b842128ce9d 100644
--- a/picoquic/picoquic_internal.h
+++ b/picoquic/picoquic_internal.h
@@ -313,8 +313,9 @@ typedef struct st_picoquic_quic_t {
     char const* ticket_file_name;
     picoquic_stored_ticket_t* p_first_ticket;
     uint32_t mtu_max;
-
     uint32_t flags;
+    uint32_t padding_multiple_default;
+    uint32_t padding_minsize_default;
 
     picoquic_stateless_packet_t* pending_stateless_packet;
 
@@ -623,6 +624,10 @@ typedef struct st_picoquic_cnx_t {
     /* Local and remote parameters */
     picoquic_tp_t local_parameters;
     picoquic_tp_t remote_parameters;
+    /* Padding policy */
+    uint32_t padding_multiple;
+    uint32_t padding_minsize;
+
     /* On clients, document the SNI and ALPN expected from the server */
     /* TODO: there may be a need to propose multiple ALPN */
     char const* sni;
diff --git a/picoquic/quicctx.c b/picoquic/quicctx.c
index e1168ed59b795ef26fa56616067d7e30b7e79af8..ab72d6c81be772d4c2796f6dc99521cce54bc21c 100644
--- a/picoquic/quicctx.c
+++ b/picoquic/quicctx.c
@@ -203,6 +203,8 @@ picoquic_quic_t* picoquic_create(uint32_t nb_connections,
         quic->cnx_id_callback_ctx = cnx_id_callback_ctx;
         quic->p_simulated_time = p_simulated_time;
         quic->local_ctx_length = 8; /* TODO: should be lower on clients-only implementation */
+        quic->padding_multiple_default = 0; /* TODO: consider default = 128 */
+        quic->padding_minsize_default = PICOQUIC_RESET_PACKET_MIN_SIZE; 
 
         if (cnx_id_callback != NULL) {
             quic->flags |= picoquic_context_unconditional_cnx_id;
@@ -273,6 +275,12 @@ int picoquic_set_default_tp(picoquic_quic_t* quic, picoquic_tp_t * tp)
     return ret;
 }
 
+void picoquic_set_default_padding(picoquic_quic_t* quic, uint32_t padding_multiple, uint32_t padding_minsize)
+{
+    quic->padding_minsize_default = padding_minsize;
+    quic->padding_multiple_default = padding_multiple;
+}
+
 void picoquic_free(picoquic_quic_t* quic)
 {
     if (quic != NULL) {
@@ -1326,6 +1334,10 @@ picoquic_cnx_t* picoquic_create_cnx(picoquic_quic_t* quic,
         cnx->max_stream_id_bidir_remote = (cnx->client_mode)?4:0;
         cnx->max_stream_id_unidir_remote = 0;
 
+        /* Initialize padding policy to default for context */
+        cnx->padding_multiple = quic->padding_multiple_default;
+        cnx->padding_minsize = quic->padding_minsize_default;
+
         if (sni != NULL) {
             cnx->sni = picoquic_string_duplicate(sni);
         }
@@ -1560,6 +1572,18 @@ uint64_t picoquic_is_0rtt_available(picoquic_cnx_t* cnx)
     return (cnx->crypto_context[1].aead_encrypt == NULL) ? 0 : 1;
 }
 
+void picoquic_cnx_set_padding_policy(picoquic_cnx_t * cnx, uint32_t padding_multiple, uint32_t padding_minsize)
+{
+    cnx->padding_multiple = padding_multiple;
+    cnx->padding_minsize = padding_minsize;
+}
+
+void picoquic_cnx_get_padding_policy(picoquic_cnx_t * cnx, uint32_t * padding_multiple, uint32_t * padding_minsize)
+{
+    *padding_multiple = cnx->padding_multiple;
+    *padding_minsize = cnx->padding_minsize;
+}
+
 /*
  * Provide clock time
  */
diff --git a/picoquic/sender.c b/picoquic/sender.c
index 065bbf544d27ba247f6e152611faf772d802470e..0d438f06b710eb7222b3b3cb510912dd0f89d2ae 100644
--- a/picoquic/sender.c
+++ b/picoquic/sender.c
@@ -174,6 +174,43 @@ int picoquic_stop_sending(picoquic_cnx_t* cnx,
     return ret;
 }
 
+/*
+ * Manage content padding
+ */
+
+uint32_t picoquic_pad_to_target_length(uint8_t * bytes, uint32_t length, uint32_t target)
+{
+    if (length < target) {
+        memset(bytes + length, 0, target - length);
+        length = target;
+    }
+
+    return length;
+}
+
+uint32_t picoquic_pad_to_policy(picoquic_cnx_t * cnx, uint8_t * bytes, uint32_t length, uint32_t max_length)
+{
+    uint32_t target = cnx->padding_minsize;
+
+    if (length > target && cnx->padding_multiple != 0) {
+        uint32_t delta = (length - target) % cnx->padding_multiple;
+
+        if (delta == 0) {
+            target = length;
+        }
+        else {
+            target = length + cnx->padding_multiple - delta;
+        }
+    }
+
+    if (target > max_length) {
+        target = max_length;
+    }
+
+    return picoquic_pad_to_target_length(bytes, length, target);
+}
+
+
 /*
  * Packet management
  */
@@ -874,9 +911,8 @@ int picoquic_retransmit_needed(picoquic_cnx_t* cnx,
                         if (ret == 0 && !frame_is_pure_ack) {
                             if (picoquic_is_stream_frame_unlimited(&p->bytes[byte_index])) {
                                 /* Need to PAD to the end of the frame to avoid sending extra bytes */
-                                while (checksum_length + length + frame_length < send_buffer_max) {
-                                    new_bytes[length] = picoquic_frame_type_padding;
-                                    length++;
+                                if (checksum_length + length + frame_length < send_buffer_max) {
+                                    length = picoquic_pad_to_target_length(new_bytes, length, (uint32_t)(send_buffer_max - checksum_length - frame_length));
                                 }
                             }
                             memcpy(&new_bytes[length], &p->bytes[byte_index], frame_length);
@@ -1161,9 +1197,10 @@ int picoquic_prepare_packet_0rtt(picoquic_cnx_t* cnx, picoquic_path_t * path_x,
         }
         /* Add padding if required */
         if (padding_required) {
-            while (length < send_buffer_max - checksum_overhead) {
-                bytes[length++] = 0;
-            }
+            length = picoquic_pad_to_target_length(bytes, length, (uint32_t)(send_buffer_max - checksum_overhead));
+        }
+        else {
+            length = picoquic_pad_to_policy(cnx, bytes, length, (uint32_t)(send_buffer_max - checksum_overhead));
         }
     }
 
@@ -1477,10 +1514,11 @@ int picoquic_prepare_packet_client_init(picoquic_cnx_t* cnx, picoquic_path_t * p
                                 cnx->original_cnxid.id_len != 0)) {
                             /* Pad to minimum packet length. But don't do that if the
                              * initial packet will be coalesced with 0-RTT packet */
-                            while (length < send_buffer_max - checksum_overhead) {
-                                bytes[length++] = 0;
-                            }
-                        } 
+                            length = picoquic_pad_to_target_length(bytes, length, (uint32_t)(send_buffer_max - checksum_overhead));
+                        }
+                        else {
+                            length = picoquic_pad_to_policy(cnx, bytes, length, (uint32_t)(send_buffer_max - checksum_overhead));
+                        }
 
                         if (packet_type == picoquic_packet_0rtt_protected) {
                             cnx->nb_zero_rtt_sent++;
@@ -2265,12 +2303,7 @@ int picoquic_prepare_packet_ready(picoquic_cnx_t* cnx, picoquic_path_t * path_x,
                     }
 
                     if (length > header_length) {
-                        if ((length + checksum_overhead) <= PICOQUIC_RESET_PACKET_MIN_SIZE) {
-                            uint32_t pad_size = PICOQUIC_RESET_PACKET_MIN_SIZE - checksum_overhead - length + 1;
-                            for (uint32_t i = 0; i < pad_size; i++) {
-                                bytes[length++] = 0;
-                            }
-                        }
+                        length = picoquic_pad_to_policy(cnx, bytes, length, (uint32_t)(send_buffer_max - checksum_overhead));
                     }
                     else if (ret == 0 && send_buffer_max > path_x->send_mtu
                         && path_x->cwin > path_x->bytes_in_transit && picoquic_is_mtu_probe_needed(cnx, path_x)) {
@@ -2497,9 +2530,7 @@ int picoquic_prepare_probe(picoquic_cnx_t* cnx,
 
                 /* Pack to min length, to verify that the path can carry a min length packet */
                 if (length + checksum_overhead < PICOQUIC_INITIAL_MTU_IPV6) {
-                    uint32_t pad_size = PICOQUIC_INITIAL_MTU_IPV6 - checksum_overhead - length;
-                    memset(&bytes[length], 0, pad_size);
-                    length += pad_size;
+                    length = picoquic_pad_to_target_length(bytes, length, PICOQUIC_INITIAL_MTU_IPV6 - checksum_overhead);
                 }
 
                 /* set the return addresses */