diff --git a/ebpfcat/ethercat.py b/ebpfcat/ethercat.py
index 3560ed025d25a568fe0de41f9d9607beaa2cef2d..194da3b4c4a0ef5199d57bc1dddacdc16252e9fd 100644
--- a/ebpfcat/ethercat.py
+++ b/ebpfcat/ethercat.py
@@ -2,7 +2,7 @@
 
 this modules contains the code to actually talk to EtherCAT terminals.
 """
-from asyncio import ensure_future, Event, Future, gather, get_event_loop, Protocol, Queue
+from asyncio import ensure_future, Event, Future, gather, get_event_loop, Protocol, Queue, Lock
 from enum import Enum
 from random import randint
 from socket import socket, AF_PACKET, SOCK_DGRAM
@@ -352,6 +352,7 @@ class Terminal:
         #     await read_eeprom(0x18, "<HHHH")
 
         self.mbx_cnt = 1
+        self.mbx_lock = Lock()
 
         self.eeprom = await self.read_eeprom()
         await self.write(0x800, data=0x80)  # empty out sync manager
@@ -482,24 +483,29 @@ class Terminal:
 
     async def mbx_send(self, type, *args, data=None, address=0, priority=0, channel=0):
         """send data to the mailbox"""
-        status, = await self.read(0x805, "B")  # always using mailbox 0, OK?
-        if status & 8:
-            raise RuntimeError("mailbox full, read first")
-        await gather(self.write(self.mbx_out_off, "HHBB", datasize(args, data),
-                                address, channel | priority << 6,
-                                type.value | self.mbx_cnt << 4,
-                                *args, data=data),
-                     self.write(self.mbx_out_off + self.mbx_out_sz - 1, data=1)
-                    )
-        self.mbx_cnt = self.mbx_cnt % 7 + 1  # yes, we start at 1 not 0
+        async with self.mbx_lock:
+            status, = await self.read(0x805, "B")  # always using mailbox 0, OK?
+            if status & 8:
+                raise RuntimeError("mailbox full, read first")
+            await gather(self.write(self.mbx_out_off, "HHBB",
+                                    datasize(args, data),
+                                    address, channel | priority << 6,
+                                    type.value | self.mbx_cnt << 4,
+                                    *args, data=data),
+                         self.write(self.mbx_out_off + self.mbx_out_sz - 1,
+                                    data=1)
+                        )
+            self.mbx_cnt = self.mbx_cnt % 7 + 1  # yes, we start at 1 not 0
 
     async def mbx_recv(self):
         """receive data from the mailbox"""
         status = 0
-        while status & 8 == 0:
-            status, = await self.read(0x80D, "B")  # always using mailbox 1, OK?
-        dlen, address, prio, type, data = await self.read(
-                self.mbx_in_off, "HHBB", data=self.mbx_in_sz - 6)
+        async with self.mbx_lock:
+            while status & 8 == 0:
+                # always using mailbox 1, OK?
+                status, = await self.read(0x80D, "B")
+            dlen, address, prio, type, data = await self.read(
+                    self.mbx_in_off, "HHBB", data=self.mbx_in_sz - 6)
         return MBXType(type & 0xf), data[:dlen]
 
     async def coe_request(self, coecmd, odcmd, *args, **kwargs):