diff --git a/extmod/modlwip.c b/extmod/modlwip.c
index 6960546f68448f181865085df9e6a83ec92c64a3..d501f4be2aecfe5ce6035f2bd3fe2b79ce73752a 100644
--- a/extmod/modlwip.c
+++ b/extmod/modlwip.c
@@ -859,15 +859,28 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_listen_obj, lwip_socket_listen);
 STATIC mp_obj_t lwip_socket_accept(mp_obj_t self_in) {
     lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in);
 
-    if (socket->pcb.tcp == NULL) {
-        mp_raise_OSError(MP_EBADF);
-    }
     if (socket->type != MOD_NETWORK_SOCK_STREAM) {
         mp_raise_OSError(MP_EOPNOTSUPP);
     }
+
+    // Create new socket object, do it here because we must not raise an out-of-memory
+    // exception when the LWIP concurrency lock is held
+    lwip_socket_obj_t *socket2 = m_new_obj_with_finaliser(lwip_socket_obj_t);
+    socket2->base.type = &lwip_socket_type;
+
+    MICROPY_PY_LWIP_ENTER
+
+    if (socket->pcb.tcp == NULL) {
+        MICROPY_PY_LWIP_EXIT
+        m_del_obj(lwip_socket_obj_t, socket2);
+        mp_raise_OSError(MP_EBADF);
+    }
+
     // I need to do this because "tcp_accepted", later, is a macro.
     struct tcp_pcb *listener = socket->pcb.tcp;
     if (listener->state != LISTEN) {
+        MICROPY_PY_LWIP_EXIT
+        m_del_obj(lwip_socket_obj_t, socket2);
         mp_raise_OSError(MP_EINVAL);
     }
 
@@ -875,26 +888,29 @@ STATIC mp_obj_t lwip_socket_accept(mp_obj_t self_in) {
     struct tcp_pcb *volatile *incoming_connection = &lwip_socket_incoming_array(socket)[socket->incoming.connection.iget];
     if (*incoming_connection == NULL) {
         if (socket->timeout == 0) {
+            MICROPY_PY_LWIP_EXIT
+            m_del_obj(lwip_socket_obj_t, socket2);
             mp_raise_OSError(MP_EAGAIN);
         } else if (socket->timeout != -1) {
-            for (mp_uint_t retries = socket->timeout / 100; retries--;) {
+            mp_uint_t retries = socket->timeout / 100;
+            while (*incoming_connection == NULL) {
+                MICROPY_PY_LWIP_EXIT
+                if (retries-- == 0) {
+                    m_del_obj(lwip_socket_obj_t, socket2);
+                    mp_raise_OSError(MP_ETIMEDOUT);
+                }
                 mp_hal_delay_ms(100);
-                if (*incoming_connection != NULL) break;
-            }
-            if (*incoming_connection == NULL) {
-                mp_raise_OSError(MP_ETIMEDOUT);
+                MICROPY_PY_LWIP_REENTER
             }
         } else {
             while (*incoming_connection == NULL) {
+                MICROPY_PY_LWIP_EXIT
                 poll_sockets();
+                MICROPY_PY_LWIP_REENTER
             }
         }
     }
 
-    // create new socket object
-    lwip_socket_obj_t *socket2 = m_new_obj_with_finaliser(lwip_socket_obj_t);
-    socket2->base.type = &lwip_socket_type;
-
     // We get a new pcb handle...
     socket2->pcb.tcp = *incoming_connection;
     if (++socket->incoming.connection.iget >= socket->incoming.connection.alloc) {
@@ -916,6 +932,8 @@ STATIC mp_obj_t lwip_socket_accept(mp_obj_t self_in) {
 
     tcp_accepted(listener);
 
+    MICROPY_PY_LWIP_EXIT
+
     // make the return value
     uint8_t ip[NETUTILS_IPV4ADDR_BUFSIZE];
     memcpy(ip, &(socket2->pcb.tcp->remote_ip), sizeof(ip));