An upload that fails at a size boundary is a limit - see 413 Request Entity Too Large. An upload that fails part-way through, at no consistent size, with the connection simply dropping, is a timeout somewhere along the path.
The timeouts to raise, all of them
# nginx
client_body_timeout 300s;
client_max_body_size 512M;
send_timeout 300s;
fastcgi_read_timeout 300s;
proxy_read_timeout 300s;
; php
max_execution_time = 300
max_input_time = 300 ; the one that is forgotten - it covers the UPLOAD itself
max_input_time limits how long PHP will spend receiving the request. It is separate from max_execution_time, defaults low, and is what kills a slow upload from a phone.
Disk and temp space
df -h /tmp /var/lib/php/tmp
grep upload_tmp_dir /etc/php/8.3/fpm/php.ini
An upload is written to a temporary file first. If that filesystem fills, the write fails mid-transfer and the connection drops with no message anywhere.
Look for what was recorded
sudo tail -50 /var/log/nginx/error.log
sudo journalctl -u php8.3-fpm -n 50 --no-pager
Client intended to send too large body is the size limit. Timed out and upstream prematurely closed are the timeouts above. Nothing at all usually means the browser or a proxy gave up before the server did.
The proper fix for large files
Chunked or resumable uploads send a big file as many small requests, so no single request is long-running and a dropped connection resumes rather than starting again. For anything over a few hundred megabytes it is the only reliable answer.