diff --git a/kayobe/plugins/filter/networkd.py b/kayobe/plugins/filter/networkd.py
index dac05b303cd06204d9ba701b2e0329f62b4ddb5e..485fa2d62cbf75a1e48ee5d10781f401408615b5 100644
--- a/kayobe/plugins/filter/networkd.py
+++ b/kayobe/plugins/filter/networkd.py
@@ -176,13 +176,11 @@ def _veth_netdev(context, veth, inventory_hostname):
     """
     interface = veth['name']
     peer = veth['peer']
-    mtu = veth['mtu']
     config = [
         {
             'NetDev': [
                 {'Name': interface},
                 {'Kind': 'veth'},
-                {'MTUBytes': mtu},
             ],
         },
         {
@@ -425,6 +423,7 @@ def _veth_network(context, veth, inventory_hostname):
     """
     interface = veth['name']
     bridge = veth['bridge']
+    mtu = veth['mtu']
     config = [
         {
             'Match': [
@@ -435,6 +434,11 @@ def _veth_network(context, veth, inventory_hostname):
             'Network': [
                 {'Bridge': bridge},
             ]
+        },
+        {
+            'Link': [
+                {'MTUBytes': mtu},
+            ]
         }
     ]
     return _filter_options(config)
@@ -448,6 +452,7 @@ def _veth_peer_network(context, veth, inventory_hostname):
     :param inventory_hostname: Ansible inventory hostname.
     """
     interface = veth['peer']
+    mtu = veth['mtu']
     config = [
         {
             'Match': [
@@ -459,6 +464,11 @@ def _veth_peer_network(context, veth, inventory_hostname):
                 # NOTE(mgoddard): bring the interface up, even without an IP.
                 {'ConfigureWithoutCarrier': 'true'},
             ]
+        },
+        {
+            'Link': [
+                {'MTUBytes': mtu},
+            ]
         }
     ]
     return _filter_options(config)
diff --git a/kayobe/tests/unit/plugins/filter/test_networkd.py b/kayobe/tests/unit/plugins/filter/test_networkd.py
index 12d2c3d6189cde782c618eb6ed373fe5bf07270c..40be13698dcb5a231a6669a78fa338e23935319c 100644
--- a/kayobe/tests/unit/plugins/filter/test_networkd.py
+++ b/kayobe/tests/unit/plugins/filter/test_networkd.py
@@ -235,37 +235,6 @@ class TestNetworkdNetDevs(BaseNetworkdTest):
         }
         self.assertEqual(expected, devs)
 
-    def test_veth_with_mtu(self):
-        self._update_context({"external_net_names": ["net3"],
-                              "net3_mtu": 1400})
-        devs = networkd.networkd_netdevs(self.context, ["net3"])
-        expected = {
-            "50-kayobe-br0": [
-                {
-                    "NetDev": [
-                        {"Name": "br0"},
-                        {"Kind": "bridge"},
-                        {"MTUBytes": 1400},
-                    ]
-                },
-            ],
-            "50-kayobe-p-br0-phy": [
-                {
-                    "NetDev": [
-                        {"Name": "p-br0-phy"},
-                        {"Kind": "veth"},
-                        {"MTUBytes": 1400},
-                    ]
-                },
-                {
-                    "Peer": [
-                        {"Name": "p-br0-ovs"},
-                    ]
-                },
-            ]
-        }
-        self.assertEqual(expected, devs)
-
     def test_veth_no_interface(self):
         self._update_context({"external_net_names": ["net3"],
                               "net3_interface": None})
@@ -870,6 +839,61 @@ class TestNetworkdNetworks(BaseNetworkdTest):
         }
         self.assertEqual(expected, nets)
 
+    def test_veth_with_mtu(self):
+        self._update_context({"external_net_names": ["net3"],
+                              "net3_bridge_ports": [],
+                              "net3_mtu": 1400})
+        nets = networkd.networkd_networks(self.context, ["net3"])
+        expected = {
+            "50-kayobe-br0": [
+                {
+                    "Match": [
+                        {"Name": "br0"}
+                    ]
+                },
+                {
+                    "Link": [
+                        {"MTUBytes": 1400},
+                    ]
+                },
+            ],
+            "50-kayobe-p-br0-phy": [
+                {
+                    "Match": [
+                        {"Name": "p-br0-phy"}
+                    ]
+                },
+                {
+                    "Network": [
+                        {"Bridge": "br0"},
+                    ]
+                },
+                {
+                    "Link": [
+                        {"MTUBytes": 1400},
+                    ]
+                },
+            ],
+            "50-kayobe-p-br0-ovs": [
+                {
+                    "Match": [
+                        {"Name": "p-br0-ovs"}
+                    ]
+                },
+                {
+                    "Network": [
+                        {"ConfigureWithoutCarrier": "true"},
+                    ]
+                },
+                {
+                    "Link": [
+                        {"MTUBytes": 1400},
+                    ]
+                },
+            ],
+        }
+        self.assertEqual(expected, nets)
+
     def test_veth_on_vlan(self):
         # Test the case where a VLAN interface is one of the networks that
         # needs patching to OVS. The parent interface is a bridge, and the veth
diff --git a/releasenotes/notes/story-2009072-57e5d079e182e763.yaml b/releasenotes/notes/story-2009072-57e5d079e182e763.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..5166556aadfbb331bdb9c8ffb201d9940c41ff6c
--- /dev/null
+++ b/releasenotes/notes/story-2009072-57e5d079e182e763.yaml
@@ -0,0 +1,6 @@
+---
+fixes:
+  - |
+    Fixes an issue with systemd-networkd MTU mismatch in veth pair on Ubuntu.
+    See `story 2009072 <https://storyboard.openstack.org/#!/story/2009072>`__
+    for details.