diff --git a/NEWS b/NEWS
index 13008ba..4ee43cf 100644
--- a/NEWS
+++ b/NEWS
@@ -16,6 +16,8 @@ Post-v2.9.0
        conntrack fragmentation support.
      * New "ovs-appctl dpctl/ipf-set-minfragment" command for userspace
        datapath conntrack fragmentation support.
+     * New "ovs-appctl dpctl/ipf-set-maxfrags" command for userspace datapath
+       conntrack fragmentation support.
    - ovs-vsctl: New commands "add-bond-iface" and "del-bond-iface".
    - OpenFlow:
      * OFPT_ROLE_STATUS is now available in OpenFlow 1.3.
diff --git a/lib/ct-dpif.c b/lib/ct-dpif.c
index 4a93bf6..81f9d92 100644
--- a/lib/ct-dpif.c
+++ b/lib/ct-dpif.c
@@ -180,6 +180,14 @@ ct_dpif_ipf_set_min_frag(struct dpif *dpif, bool v6, uint32_t min_frag)
             : EOPNOTSUPP);
 }
 
+int
+ct_dpif_ipf_set_nfrag_max(struct dpif *dpif, uint32_t max_frags)
+{
+    return (dpif->dpif_class->ipf_set_nfrag_max
+            ? dpif->dpif_class->ipf_set_nfrag_max(dpif, max_frags)
+            : EOPNOTSUPP);
+}
+
 void
 ct_dpif_entry_uninit(struct ct_dpif_entry *entry)
 {
diff --git a/lib/ct-dpif.h b/lib/ct-dpif.h
index 449f958..4ce4dd4 100644
--- a/lib/ct-dpif.h
+++ b/lib/ct-dpif.h
@@ -202,6 +202,7 @@ int ct_dpif_get_maxconns(struct dpif *dpif, uint32_t *maxconns);
 int ct_dpif_get_nconns(struct dpif *dpif, uint32_t *nconns);
 int ct_dpif_ipf_change_enabled(struct dpif *, bool, bool);
 int ct_dpif_ipf_set_min_frag(struct dpif *, bool, uint32_t);
+int ct_dpif_ipf_set_nfrag_max(struct dpif *, uint32_t);
 void ct_dpif_entry_uninit(struct ct_dpif_entry *);
 void ct_dpif_format_entry(const struct ct_dpif_entry *, struct ds *,
                           bool verbose, bool print_stats);
diff --git a/lib/dpctl.c b/lib/dpctl.c
index f6c0a87..f25c6fc 100644
--- a/lib/dpctl.c
+++ b/lib/dpctl.c
@@ -1824,6 +1824,35 @@ dpctl_ct_ipf_set_min_frag(int argc, const char *argv[],
     return error;
 }
 
+static int
+dpctl_ct_ipf_set_nfrag_max(int argc, const char *argv[],
+                           struct dpctl_params *dpctl_p)
+{
+    struct dpif *dpif;
+    int error = dpctl_ct_open_dp(argc, argv, dpctl_p, &dpif, 3);
+    if (!error) {
+        uint32_t nfrags_max;
+        if (ovs_scan(argv[argc - 1], "%"SCNu32, &nfrags_max)) {
+            error = ct_dpif_ipf_set_nfrag_max(dpif, nfrags_max);
+
+            if (!error) {
+                dpctl_print(dpctl_p,
+                            "setting maximum fragments successful");
+            } else {
+                dpctl_error(dpctl_p, error,
+                            "setting maximum fragments failed");
+            }
+        } else {
+            error = EINVAL;
+            dpctl_error(dpctl_p, error,
+                        "parameter missing for maximum fragments");
+        }
+        dpif_close(dpif);
+    }
+
+    return error;
+}
+
 /* Undocumented commands for unit testing. */
 
 static int
@@ -2127,6 +2156,8 @@ static const struct dpctl_command all_commands[] = {
        dpctl_ct_ipf_change_enabled, DP_RW },
     { "ipf-set-minfragment", "[dp] v4_or_v6 minfragment", 2, 3,
        dpctl_ct_ipf_set_min_frag, DP_RW },
+    { "ipf-set-maxfrags", "[dp] maxfrags", 1, 2,
+       dpctl_ct_ipf_set_nfrag_max, DP_RW },
     { "help", "", 0, INT_MAX, dpctl_help, DP_RO },
     { "list-commands", "", 0, INT_MAX, dpctl_list_commands, DP_RO },
 
diff --git a/lib/dpctl.man b/lib/dpctl.man
index 6223c15..43cff05 100644
--- a/lib/dpctl.man
+++ b/lib/dpctl.man
@@ -286,3 +286,11 @@ Sets the minimum fragment size supported by the userspace datapath
 connection tracker.  Either v4 or v6 must be specified.  The default v4
 value is 1200 and the clamped minimum is 400.  The default v6 value is
 1280, which is also the clamped minimum.
+.
+.TP
+\*(DX\fBipf\-set\-maxfrags\fR [\fIdp\fR] \fBmaxfrags\fR
+Sets the maximum number of fragments tracked by the userspace datapath
+connection tracker.  The default value is 1000 and the clamped maximum
+is 5000.  Note that packet buffers can be held by the fragmentation
+module while fragments are incomplete, but will timeout after 15 seconds.
+Memory pool sizing should be set accordingly when fragmentation is enabled.
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index f51fe52..542478d 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -5885,6 +5885,13 @@ dpif_netdev_ipf_set_min_frag(struct dpif *dpif OVS_UNUSED, bool v6,
     return ipf_set_min_frag(v6, min_frag);
 }
 
+static int
+dpif_netdev_ipf_set_nfrag_max(struct dpif *dpif OVS_UNUSED,
+                              uint32_t max_frags)
+{
+    return ipf_set_nfrag_max(max_frags);
+}
+
 const struct dpif_class dpif_netdev_class = {
     "netdev",
     dpif_netdev_init,
@@ -5935,6 +5942,7 @@ const struct dpif_class dpif_netdev_class = {
     dpif_netdev_ct_get_nconns,
     dpif_netdev_ipf_change_enabled,
     dpif_netdev_ipf_set_min_frag,
+    dpif_netdev_ipf_set_nfrag_max,
     dpif_netdev_meter_get_features,
     dpif_netdev_meter_set,
     dpif_netdev_meter_get,
diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c
index d9333ed..e8575d9 100644
--- a/lib/dpif-netlink.c
+++ b/lib/dpif-netlink.c
@@ -2996,6 +2996,7 @@ const struct dpif_class dpif_netlink_class = {
     NULL,                       /* ct_get_nconns */
     NULL,                       /* ipf_change_enabled */
     NULL,                       /* ipf_set_min_frag */
+    NULL,                       /* ipf_set_nfrag_max */
     dpif_netlink_meter_get_features,
     dpif_netlink_meter_set,
     dpif_netlink_meter_get,
diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h
index aa9c490..7679169 100644
--- a/lib/dpif-provider.h
+++ b/lib/dpif-provider.h
@@ -448,6 +448,8 @@ struct dpif_class {
     int (*ipf_change_enabled)(struct dpif *, bool, bool);
     /* Set minimum fragment allowed. */
     int (*ipf_set_min_frag)(struct dpif *, bool, uint32_t);
+    /* Set maximum number of fragments tracked. */
+    int (*ipf_set_nfrag_max)(struct dpif *, uint32_t);
     /* Meters */
 
     /* Queries 'dpif' for supported meter features.
diff --git a/lib/ipf.c b/lib/ipf.c
index 24d9b06..78221f4 100644
--- a/lib/ipf.c
+++ b/lib/ipf.c
@@ -1274,3 +1274,13 @@ ipf_set_min_frag(bool v6, uint32_t value)
     ipf_lock_unlock(&ipf_lock);
     return 0;
 }
+
+int
+ipf_set_nfrag_max(uint32_t value)
+{
+    if (value > IPF_NFRAG_UBOUND) {
+        return 1;
+    }
+    atomic_store_relaxed(&nfrag_max, value);
+    return 0;
+}
diff --git a/lib/ipf.h b/lib/ipf.h
index 277852d..fb24078 100644
--- a/lib/ipf.h
+++ b/lib/ipf.h
@@ -66,4 +66,7 @@ ipf_change_enabled(bool v6, bool enable);
 int
 ipf_set_min_frag(bool v6, uint32_t value);
 
+int
+ipf_set_nfrag_max(uint32_t value);
+
 #endif /* ipf.h */
