To enable BBR on CentOS Stream 9, load the kernel module, select BBR with sysctl, and pair it with the fq packet scheduler. The change takes about five minutes, works without opening a firewall port, and can be made persistent across reboots.
Prerequisites
- A CentOS Stream 9 VPS with its standard 5.14-series kernel or another kernel that provides the
tcp_bbrmodule. - SSH access as
root, or a regular account with workingsudoprivileges. - Permission to load kernel modules, change kernel parameters, and modify files below
/etc; an unprivileged container may deny these operations. - No domain, web server, extra RAM, or extra disk is required because BBR is a kernel-level TCP setting.
- If you need the server first, choose a Linux VPS from VPSLake and install CentOS Stream 9.
BBR changes TCP congestion control and packet pacing. It cannot raise your VPS bandwidth limit, and the result depends on the route, the remote peer, and the traffic your application sends.
Step 1: Check the CentOS release and current TCP settings
Confirm the release and running kernel before changing network parameters so you do not troubleshoot a provider image or custom kernel as if it were the standard installation.
cat /etc/centos-release
uname -r
sysctl net.ipv4.tcp_available_congestion_control
sysctl net.ipv4.tcp_congestion_control
CentOS Stream 9 should be identified on the first line. A standard image normally reports a 5.14 kernel; the active algorithm is often cubic, and bbr may not appear until its module is loaded.
CentOS Stream release 9 (Plow)
5.14.0-...el9.x86_64
net.ipv4.tcp_available_congestion_control = reno cubic
net.ipv4.tcp_congestion_control = cubic
The exact kernel revision and algorithm order vary as Stream receives updates. Keep a newer working provider kernel; it does not need to match the sample output.
Step 2: Load BBR into the running kernel
The kernel must register BBR before sysctl can select it, so load the module and check the available algorithms in the same SSH session.
sudo modprobe tcp_bbr
sysctl net.ipv4.tcp_available_congestion_control
modprobe is silent when it succeeds. The second command should now include bbr, although the order may differ:
net.ipv4.tcp_available_congestion_control = reno cubic bbr
Loading the module makes BBR available for this boot; it does not yet select BBR for new connections. If the command reports that the module cannot be found, stop here and use the first troubleshooting section rather than writing a setting that the kernel cannot apply.
Step 3: Persist the module and congestion-control settings
Keep the boot-time module request separate from the sysctl file so each change is easy to inspect, undo, or diagnose after a kernel update.
sudo tee /etc/modules-load.d/tcp-bbr.conf >/dev/null <<'EOF'
tcp_bbr
EOF
sudo tee /etc/sysctl.d/99-tcp-bbr.conf >/dev/null <<'EOF'
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
EOF
sudo sysctl -p /etc/sysctl.d/99-tcp-bbr.conf
The first file asks systemd-modules-load to load tcp_bbr during future boots. The second selects BBR for new TCP connections and sets fair queueing as the default for interfaces initialized later; the final command applies both values immediately.
Expected output:
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
CentOS Stream 9 follows the EL9 layout for persistent kernel parameters. See Red Hat’s RHEL 9 kernel-parameter documentation for the /etc/sysctl.d/ method.
Step 4: Put fq on the active network interface
Changing net.core.default_qdisc sets the default for interfaces created later, but an interface already carrying your SSH connection may still have the usual fq_codel queue.
MAIN_IFACE=$(ip -o route show default | awk '$1 == "default" {print $5; exit}')
printf '%s\n' "$MAIN_IFACE"
tc qdisc show dev "$MAIN_IFACE"
The first command should print a device such as ens3 or eth0. If the last command does not show qdisc fq, replace the live root queue for the current boot:
MAIN_IFACE=$(ip -o route show default | awk '$1 == "default" {print $5; exit}')
sudo tc qdisc replace dev "$MAIN_IFACE" root fq
tc qdisc show dev "$MAIN_IFACE"
Look for qdisc fq in the result:
ens3
qdisc fq 0: root refcnt 2 limit 10000p buckets 1024
This runtime change can disappear when NetworkManager recreates the link. To retain it in the active NetworkManager profile, store that profile name and activate it:
CONNECTION_NAME=$(nmcli -g GENERAL.CONNECTION device show "$MAIN_IFACE")
printf '%s\n' "$CONNECTION_NAME"
sudo nmcli connection modify "$CONNECTION_NAME" tc.qdiscs 'root fq'
sudo nmcli connection up "$CONNECTION_NAME"
The first command should print the active profile name. Bringing the connection up can briefly interrupt SSH, so use the VPS control panel’s VNC console if you cannot risk losing the session. Red Hat’s RHEL 9 traffic-control guide documents the tc.qdiscs NetworkManager setting.
Verify BBR on CentOS Stream 9
Run one final check to confirm that BBR is active, the two configuration files contain the intended values, and the default-route interface is using fq.
MAIN_IFACE=$(ip -o route show default | awk '$1 == "default" {print $5; exit}')
sysctl net.ipv4.tcp_congestion_control net.core.default_qdisc
sysctl net.ipv4.tcp_available_congestion_control
grep -Ev '^[[:space:]]*(#|$)' /etc/sysctl.d/99-tcp-bbr.conf
grep -Fx 'tcp_bbr' /etc/modules-load.d/tcp-bbr.conf
tc qdisc show dev "$MAIN_IFACE"
You want tcp_congestion_control = bbr, default_qdisc = fq, bbr in the available list, both assignments from 99-tcp-bbr.conf, the line tcp_bbr, and qdisc fq for the active device. The algorithm is chosen when a TCP connection is created, so reconnect SSH or restart a long-lived service before comparing its traffic.
net.ipv4.tcp_congestion_control = bbr
net.core.default_qdisc = fq
net.ipv4.tcp_available_congestion_control = reno cubic bbr
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
tcp_bbr
qdisc fq 0: root refcnt 2 limit 10000p buckets 1024
Troubleshooting
modprobe: FATAL: Module tcp_bbr not found
The running kernel does not expose BBR, or the matching module package is missing. Install the EL9 extra modules package, reboot into the newest installed kernel, and repeat Step 2:
sudo dnf install -y kernel-modules-extra
sudo reboot
After reconnecting, run uname -r and sudo modprobe tcp_bbr again. If DNF cannot provide a matching package or the VPS keeps booting a provider-managed custom kernel, ask the provider for a standard CentOS Stream 9 kernel with BBR support instead of copying a module from another kernel.
sysctl: cannot set net.ipv4.tcp_congestion_control
BBR was selected before the module was registered. Load it, confirm that bbr appears, and apply the saved file again:
sudo modprobe tcp_bbr
sysctl net.ipv4.tcp_available_congestion_control
sudo sysctl -p /etc/sysctl.d/99-tcp-bbr.conf
If the error returns after every reboot, check that /etc/modules-load.d/tcp-bbr.conf contains exactly tcp_bbr and that uname -r still shows the kernel you repaired.
RTNETLINK answers: Operation not permitted
The VPS is likely an unprivileged container without the capability needed to change traffic control. BBR may still work as the active TCP algorithm, but the container cannot attach fq; the host administrator must apply that qdisc, or you need a full VPS with traffic-control permissions.
BBR changes back to cubic after a reboot
Another sysctl file may be loaded later and override the local value, or the module was not loaded early enough. Find conflicting assignments, then reload the module and saved settings:
grep -RnsE 'tcp_congestion_control|default_qdisc' /etc/sysctl.conf /etc/sysctl.d /usr/lib/sysctl.d 2>/dev/null
sudo systemctl restart systemd-modules-load
sudo sysctl -p /etc/sysctl.d/99-tcp-bbr.conf
sysctl net.ipv4.tcp_available_congestion_control net.ipv4.tcp_congestion_control
Remove or update the conflicting assignment rather than adding a second BBR file with another name.
FAQ
Does enabling BBR increase my VPS bandwidth?
No. BBR changes TCP pacing and capacity estimation, but it cannot raise your plan’s network limit or make a slow remote server send faster. Compare the routes and applications that matter to you instead of assuming every transfer will improve.
Do I need to change firewalld for BBR?
No. BBR is a kernel setting and does not create a listener or open an inbound port. Leave your existing SSH and application rules in place.
Will BBR affect UDP traffic?
No. The net.ipv4.tcp_congestion_control parameter applies to TCP only. UDP software must provide its own rate-control behavior, so this setting does not tune DNS, WireGuard, or other UDP services.
How do I return to CUBIC?
Change net.ipv4.tcp_congestion_control = bbr to cubic in /etc/sysctl.d/99-tcp-bbr.conf, then run sudo sysctl -p /etc/sysctl.d/99-tcp-bbr.conf. You can leave tcp_bbr in the module-load file because loading a module does not select it as the active algorithm.