When using the optional ftplib.FTP()'s timeout parameter which specifies a timeout in seconds for blocking operations like the connection attempt, it is applied on both FTP control and passive data channel (if any). It is not applied for active (PORT/EPRT) data connections. The patch in attachment modifies ftplib so that when ntransfer method is called in active mode, timeout is applied on the resulting data connection.
I'm sorry, I realized right now that settimeout() should be used also *before* invoking accept(), to avoid the client to stall in case the server does not establish any connection. The second patch in attachment does that by using settimeout() straight into FTP.makeport() method.
This time it's not easy as I see no way to distinguish whether the timeout exception gets raised by the command or the control socket, as makeport() method implementation deals with both: host = self.sock.getsockname()[0] if self.af == socket.AF_INET: resp = self.sendport(host, port) # socket.timeout can be raised here else: resp = self.sendeprt(host, port) # ...here if self.timeout is not _GLOBAL_DEFAULT_TIMEOUT: sock.settimeout(self.timeout) # or here I think the best we can do is add a test which checks the timeout applied to the data socket resulting from a PASV/PORT request. That doesn't cover this specific bug at all but it's something which is currently missing and that it would be nice to have.