diff --git a/NEWS b/NEWS
index 77c2b43..bdbe7e2 100644
--- a/NEWS
+++ b/NEWS
@@ -12,6 +12,8 @@ Post-v2.9.0
        default it always accepts names and in interactive use it displays them;
        use --names or --no-names to override.  See ovs-ofctl(8) for details.
    - ovs-vsctl: New commands "add-bond-iface" and "del-bond-iface".
+   - ovs-appctl:
+     * New command "lacp/show-stats"
    - OpenFlow:
      * OFPT_ROLE_STATUS is now available in OpenFlow 1.3.
    - Linux kernel 4.14
diff --git a/lib/lacp.c b/lib/lacp.c
index fdefeda..8353746 100644
--- a/lib/lacp.c
+++ b/lib/lacp.c
@@ -127,9 +127,12 @@ struct slave {
     struct timer tx;              /* Next message transmission timer. */
     struct timer rx;              /* Expected message receive timer. */
 
-    uint32_t count_rx_pdus;       /* dot3adAggPortStatsLACPDUsRx */
-    uint32_t count_rx_pdus_bad;   /* dot3adAggPortStatsIllegalRx */
-    uint32_t count_tx_pdus;       /* dot3adAggPortStatsLACPDUsTx */
+    uint32_t count_rx_pdus;         /* dot3adAggPortStatsLACPDUsRx */
+    uint32_t count_rx_pdus_bad;     /* dot3adAggPortStatsIllegalRx */
+    uint32_t count_tx_pdus;         /* dot3adAggPortStatsLACPDUsTx */
+    uint32_t count_link_expired;    /* Num of times link expired */
+    uint32_t count_link_defaulted;  /* Num of times link defaulted */
+    uint32_t count_carrier_changed; /* Num of times link status changed */
 };
 
 static struct ovs_mutex mutex;
@@ -153,6 +156,7 @@ static bool info_tx_equal(struct lacp_info *, struct lacp_info *)
     OVS_REQUIRES(mutex);
 
 static unixctl_cb_func lacp_unixctl_show;
+static unixctl_cb_func lacp_unixctl_show_stats;
 
 /* Populates 'pdu' with a LACP PDU comprised of 'actor' and 'partner'. */
 static void
@@ -206,6 +210,8 @@ lacp_init(void)
 {
     unixctl_command_register("lacp/show", "[port]", 0, 1,
                              lacp_unixctl_show, NULL);
+    unixctl_command_register("lacp/show-stats", "[port]", 0, 1,
+                             lacp_unixctl_show_stats, NULL);
 }
 
 static void
@@ -459,6 +465,7 @@ lacp_slave_carrier_changed(const struct lacp *lacp, const void *slave_)
     if (slave->status == LACP_CURRENT || slave->lacp->active) {
         slave_set_expired(slave);
     }
+    slave->count_carrier_changed++;
 
 out:
     lacp_unlock();
@@ -525,8 +532,10 @@ lacp_run(struct lacp *lacp, lacp_send_pdu *send_pdu) OVS_EXCLUDED(mutex)
 
             if (slave->status == LACP_CURRENT) {
                 slave_set_expired(slave);
+                slave->count_link_expired++;
             } else if (slave->status == LACP_EXPIRED) {
                 slave_set_defaulted(slave);
+                slave->count_link_defaulted++;
             }
             if (slave->status != old_status) {
                 seq_change(connectivity_seq_get());
@@ -994,6 +1003,40 @@ lacp_print_details(struct ds *ds, struct lacp *lacp) OVS_REQUIRES(mutex)
 }
 
 static void
+lacp_print_stats(struct ds *ds, struct lacp *lacp) OVS_REQUIRES(mutex)
+{
+    struct shash slave_shash = SHASH_INITIALIZER(&slave_shash);
+    const struct shash_node **sorted_slaves = NULL;
+
+    struct slave *slave;
+    int i;
+
+    ds_put_format(ds, "---- %s statistics ----\n", lacp->name);
+
+    HMAP_FOR_EACH (slave, node, &lacp->slaves) {
+        shash_add(&slave_shash, slave->name, slave);
+    }
+    sorted_slaves = shash_sort(&slave_shash);
+
+    for (i = 0; i < shash_count(&slave_shash); i++) {
+        slave = sorted_slaves[i]->data;
+        ds_put_format(ds, "\nslave: %s:\n", slave->name);
+        ds_put_format(ds, "\tRX PDUs: %u\n", slave->count_rx_pdus);
+        ds_put_format(ds, "\tRX Bad PDUs: %u\n", slave->count_rx_pdus_bad);
+        ds_put_format(ds, "\tTX PDUs: %u\n", slave->count_tx_pdus);
+        ds_put_format(ds, "\tLink Expired: %u\n",
+                      slave->count_link_expired);
+        ds_put_format(ds, "\tLink Defaulted: %u\n",
+                      slave->count_link_defaulted);
+        ds_put_format(ds, "\tCarrier Status Changed: %u\n",
+                      slave->count_carrier_changed);
+    }
+
+    shash_destroy(&slave_shash);
+    free(sorted_slaves);
+}
+
+static void
 lacp_unixctl_show(struct unixctl_conn *conn, int argc, const char *argv[],
                   void *aux OVS_UNUSED) OVS_EXCLUDED(mutex)
 {
@@ -1021,6 +1064,36 @@ out:
     lacp_unlock();
 }
 
+static void
+lacp_unixctl_show_stats(struct unixctl_conn *conn,
+                  int argc,
+                  const char *argv[],
+                  void *aux OVS_UNUSED) OVS_EXCLUDED(mutex)
+{
+    struct ds ds = DS_EMPTY_INITIALIZER;
+    struct lacp *lacp;
+
+    lacp_lock();
+    if (argc > 1) {
+        lacp = lacp_find(argv[1]);
+        if (!lacp) {
+            unixctl_command_reply_error(conn, "no such lacp object");
+            goto out;
+        }
+        lacp_print_stats(&ds, lacp);
+    } else {
+        LIST_FOR_EACH (lacp, node, all_lacps) {
+            lacp_print_stats(&ds, lacp);
+        }
+    }
+
+    unixctl_command_reply(conn, ds_cstr(&ds));
+    ds_destroy(&ds);
+
+out:
+    lacp_unlock();
+}
+
 /* Extract a snapshot of the current state and counters for a slave port.
    Return false if the slave is not active. */
 bool
diff --git a/vswitchd/ovs-vswitchd.8.in b/vswitchd/ovs-vswitchd.8.in
index 80e5f53..b6f1929 100644
--- a/vswitchd/ovs-vswitchd.8.in
+++ b/vswitchd/ovs-vswitchd.8.in
@@ -240,6 +240,12 @@ whether it is attached or detached, port id and priority, actor
 information, and partner information.  If \fIport\fR is not specified,
 then displays detailed information about all interfaces with CFM
 enabled.
+.
+.IP "\fBlacp/stats-show\fR [\fIport\fR]"
+Lists various stats about LACP PDUs (number of RX/TX PDUs, bad PDUs received)
+and slave state (number of time slave's state expired/defaulted and carrier
+status changed) for the given \fIport\fR.  If \fIport\fR is not specified,
+then displays stats of all interfaces with LACP enabled.
 .SS "DPCTL DATAPATH DEBUGGING COMMANDS"
 The primary way to configure \fBovs\-vswitchd\fR is through the Open
 vSwitch database, e.g. using \fBovs\-vsctl\fR(8).  These commands
