diff --git a/include/openvswitch/ofp-util.h b/include/openvswitch/ofp-util.h
index 91ff0c2..b197a9a 100644
--- a/include/openvswitch/ofp-util.h
+++ b/include/openvswitch/ofp-util.h
@@ -1083,7 +1083,7 @@ struct ofputil_flow_update {
     uint8_t table_id;
     uint16_t priority;
     ovs_be64 cookie;
-    struct match *match;
+    struct match match;
     const struct ofpact *ofpacts;
     size_t ofpacts_len;
 
@@ -1095,7 +1095,8 @@ int ofputil_decode_flow_update(struct ofputil_flow_update *,
                                struct ofpbuf *msg, struct ofpbuf *ofpacts);
 void ofputil_start_flow_update(struct ovs_list *replies);
 void ofputil_append_flow_update(const struct ofputil_flow_update *,
-                                struct ovs_list *replies);
+                                struct ovs_list *replies,
+                                const struct tun_table *);
 
 /* Abstract nx_flow_monitor_cancel. */
 uint32_t ofputil_decode_flow_monitor_cancel(const struct ofp_header *);
diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index 7b7c430..dacaa07 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -2371,10 +2371,8 @@ ofp_print_nxst_flow_monitor_reply(struct ds *string,
     for (;;) {
         char reasonbuf[OFP_FLOW_REMOVED_REASON_BUFSIZE];
         struct ofputil_flow_update update;
-        struct match match;
         int retval;
 
-        update.match = &match;
         retval = ofputil_decode_flow_update(&update, &b, &ofpacts);
         if (retval) {
             if (retval != EOF) {
@@ -2418,7 +2416,7 @@ ofp_print_nxst_flow_monitor_reply(struct ds *string,
         ds_put_format(string, " cookie=%#"PRIx64, ntohll(update.cookie));
 
         ds_put_char(string, ' ');
-        match_format(update.match, string, OFP_DEFAULT_PRIORITY);
+        match_format(&update.match, string, OFP_DEFAULT_PRIORITY);
 
         if (update.ofpacts_len) {
             if (string->string[string->length - 1] != ' ') {
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index b9efd32..156d8d2 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -6720,7 +6720,7 @@ ofputil_decode_flow_update(struct ofputil_flow_update *update,
         update->cookie = nfuf->cookie;
         update->priority = ntohs(nfuf->priority);
 
-        error = nx_pull_match(msg, match_len, update->match, NULL, NULL, NULL);
+        error = nx_pull_match(msg, match_len, &update->match, NULL, NULL, NULL);
         if (error) {
             return error;
         }
@@ -6782,13 +6782,20 @@ ofputil_start_flow_update(struct ovs_list *replies)
 
 void
 ofputil_append_flow_update(const struct ofputil_flow_update *update,
-                           struct ovs_list *replies)
+                           struct ovs_list *replies,
+                           const struct tun_table *tun_table)
 {
+    struct ofputil_flow_update *update_ =
+        CONST_CAST(struct ofputil_flow_update *, update);
+    const struct tun_table *orig_tun_table;
     enum ofp_version version = ofpmp_version(replies);
     struct nx_flow_update_header *nfuh;
     struct ofpbuf *msg;
     size_t start_ofs;
 
+    orig_tun_table = update->match.flow.tunnel.metadata.tab;
+    update_->match.flow.tunnel.metadata.tab = tun_table;
+
     msg = ofpbuf_from_list(ovs_list_back(replies));
     start_ofs = msg->size;
 
@@ -6802,7 +6809,7 @@ ofputil_append_flow_update(const struct ofputil_flow_update *update,
         int match_len;
 
         ofpbuf_put_zeros(msg, sizeof *nfuf);
-        match_len = nx_put_match(msg, update->match, htonll(0), htonll(0));
+        match_len = nx_put_match(msg, &update->match, htonll(0), htonll(0));
         ofpacts_put_openflow_actions(update->ofpacts, update->ofpacts_len, msg,
                                      version);
         nfuf = ofpbuf_at_assert(msg, start_ofs, sizeof *nfuf);
@@ -6820,6 +6827,7 @@ ofputil_append_flow_update(const struct ofputil_flow_update *update,
     nfuh->event = htons(update->event);
 
     ofpmp_postappend(replies, start_ofs);
+    update_->match.flow.tunnel.metadata.tab = orig_tun_table;
 }
 
 struct ofpbuf *
diff --git a/ofproto/connmgr.c b/ofproto/connmgr.c
index 1f135a4..854868e 100644
--- a/ofproto/connmgr.c
+++ b/ofproto/connmgr.c
@@ -2183,14 +2183,12 @@ ofmonitor_report(struct connmgr *mgr, struct rule *rule,
             if (flags & NXFMF_OWN || ofconn != abbrev_ofconn
                 || ofconn->monitor_paused) {
                 struct ofputil_flow_update fu;
-                struct match match;
 
                 fu.event = event;
                 fu.reason = event == NXFME_DELETED ? reason : 0;
                 fu.table_id = rule->table_id;
                 fu.cookie = rule->flow_cookie;
-                minimatch_expand(&rule->cr.match, &match);
-                fu.match = &match;
+                minimatch_expand(&rule->cr.match, &fu.match);
                 fu.priority = rule->cr.priority;
 
                 ovs_mutex_lock(&rule->mutex);
@@ -2206,13 +2204,15 @@ ofmonitor_report(struct connmgr *mgr, struct rule *rule,
                     fu.ofpacts = NULL;
                     fu.ofpacts_len = 0;
                 }
-                ofputil_append_flow_update(&fu, &ofconn->updates);
+                ofputil_append_flow_update(&fu, &ofconn->updates,
+                                           ofproto_get_tun_tab(rule->ofproto));
             } else if (!ofconn->sent_abbrev_update) {
                 struct ofputil_flow_update fu;
 
                 fu.event = NXFME_ABBREV;
                 fu.xid = abbrev_xid;
-                ofputil_append_flow_update(&fu, &ofconn->updates);
+                ofputil_append_flow_update(&fu, &ofconn->updates,
+                                           ofproto_get_tun_tab(rule->ofproto));
 
                 ofconn->sent_abbrev_update = true;
             }
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index 58295a1..5f21efc 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -5885,12 +5885,12 @@ handle_barrier_request(struct ofconn *ofconn, const struct ofp_header *oh)
 static void
 ofproto_compose_flow_refresh_update(const struct rule *rule,
                                     enum nx_flow_monitor_flags flags,
-                                    struct ovs_list *msgs)
+                                    struct ovs_list *msgs,
+                                    const struct tun_table *tun_table)
     OVS_REQUIRES(ofproto_mutex)
 {
     const struct rule_actions *actions;
     struct ofputil_flow_update fu;
-    struct match match;
 
     fu.event = (flags & (NXFMF_INITIAL | NXFMF_ADD)
                 ? NXFME_ADDED : NXFME_MODIFIED);
@@ -5901,8 +5901,7 @@ ofproto_compose_flow_refresh_update(const struct rule *rule,
     ovs_mutex_unlock(&rule->mutex);
     fu.table_id = rule->table_id;
     fu.cookie = rule->flow_cookie;
-    minimatch_expand(&rule->cr.match, &match);
-    fu.match = &match;
+    minimatch_expand(&rule->cr.match, &fu.match);
     fu.priority = rule->cr.priority;
 
     actions = flags & NXFMF_ACTIONS ? rule_get_actions(rule) : NULL;
@@ -5912,7 +5911,7 @@ ofproto_compose_flow_refresh_update(const struct rule *rule,
     if (ovs_list_is_empty(msgs)) {
         ofputil_start_flow_update(msgs);
     }
-    ofputil_append_flow_update(&fu, msgs);
+    ofputil_append_flow_update(&fu, msgs, tun_table);
 }
 
 void
@@ -5926,7 +5925,8 @@ ofmonitor_compose_refresh_updates(struct rule_collection *rules,
         enum nx_flow_monitor_flags flags = rule->monitor_flags;
         rule->monitor_flags = 0;
 
-        ofproto_compose_flow_refresh_update(rule, flags, msgs);
+        ofproto_compose_flow_refresh_update(rule, flags, msgs,
+                ofproto_get_tun_tab(rule->ofproto));
     }
 }
 
diff --git a/tests/ofproto.at b/tests/ofproto.at
index d360b7a..ad8df28 100644
--- a/tests/ofproto.at
+++ b/tests/ofproto.at
@@ -5640,3 +5640,48 @@ NXST_FLOW reply:
 
 OVS_VSWITCHD_STOP
 AT_CLEANUP
+
+AT_SETUP([ofproto - monitor flows with tun_md])
+OVS_VSWITCHD_START
+
+AT_CHECK([ovs-ofctl add-tlv-map br0 "{class=0xffff,type=0,len=4}->tun_metadata0"])
+AT_CHECK([ovs-ofctl add-flow br0 tun_metadata0=0x1,actions=drop])
+
+AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip], [0], [dnl
+NXST_FLOW reply:
+ tun_metadata0=0x1 actions=drop
+])
+
+AT_CAPTURE_FILE([ofctl_monitor.log])
+dnl Usually ovs-ofctl monitor outputs on stderr, but the first message here
+dnl is put on stdout, because it is handled by ofctl in dump_transaction()
+dnl and not in monitor_vconn().
+AT_CHECK([ovs-ofctl monitor br0 65534 watch: --detach --no-chdir --pidfile >ofctl_monitor.log 2>&1])
+
+OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 2])
+
+AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl
+NXST_FLOW_MONITOR reply:
+ event=ADDED table=0 cookie=0 tun_metadata0=0x1
+])
+
+AT_CHECK([ovs-ofctl del-flows br0])
+
+OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 4])
+
+AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl
+NXST_FLOW_MONITOR reply:
+ event=ADDED table=0 cookie=0 tun_metadata0=0x1
+NXST_FLOW_MONITOR reply:
+ event=DELETED reason=delete table=0 cookie=0 tun_metadata0=0x1
+])
+
+OVS_APP_EXIT_AND_WAIT([ovs-ofctl])
+
+dnl Check that vswitchd hasn't crashed
+AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip], [0], [dnl
+NXST_FLOW reply:
+])
+
+OVS_VSWITCHD_STOP
+AT_CLEANUP
diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c
index 7f5bb61..25e2b30 100644
--- a/utilities/ovs-ofctl.c
+++ b/utilities/ovs-ofctl.c
@@ -1811,7 +1811,7 @@ ofctl_unblock(struct unixctl_conn *conn, int argc OVS_UNUSED,
     }
 }
 
-/* Prints to stdout all of the messages received on 'vconn'.
+/* Prints to stderr all of the messages received on 'vconn'.
  *
  * Iff 'reply_to_echo_requests' is true, sends a reply to any echo request
  * received on 'vconn'.
