ROS 2 QoS Compatibility Explained: Why Your Publisher and Subscriber Won't Connect
If your ROS 2 subscriber never receives a message, even though the topic name and message type match, check the Quality of Service (QoS) settings first. ROS 2 only connects a publisher and a subscription when their QoS profiles are compatible, and the official documentation states the rule plainly: connections are only made if every policy of the requested QoS profile is not more stringent than that of the offered QoS profile. A Best effort publisher paired with a Reliable subscription never connects. Nothing is delivered, and nothing crashes.
This guide follows the ROS 2 Lyrical Luth documentation (the current LTS, released May 22, 2026). It covers the compatibility model, the tables for each policy, the tools that report a mismatch, and why the Zenoh middleware behaves differently. Every rule and command below comes from the official docs indexed in the ROS 2 knowledge base.
The request-vs-offered model in plain English
ROS 2 lets you configure QoS separately on every publisher, subscription, service server and client. That flexibility has a cost. When two ends use different profiles, they may be incompatible, and in that case messages are not delivered.
The docs describe compatibility with a Request vs Offered model. A subscription *requests* the minimum quality it is willing to accept. A publisher *offers* the maximum quality it can provide. The pair connects only if, for every policy, the request is not stricter than the offer. Three consequences are worth remembering:
- Several subscriptions with different requested profiles can connect to the same publisher at the same time.
- Whether one publisher and one subscription are compatible does not depend on the other publishers and subscriptions on the topic.
- All policies that affect compatibility must match. If reliability is compatible but durability is not, the connection is still refused.
If you are coming from ROS 1, this is new. The docs point out that in ROS 1 any publisher and subscriber with the same message type on the same topic were connected. In ROS 2, two nodes can share a topic and still never exchange a message.
Reliable vs best effort: the most common mismatch
The reliability policy has two values. Best effort attempts to deliver samples but may lose them if the network is not robust. Reliable guarantees that samples are delivered and may retry multiple times. Reliable is the stricter of the two, so the documentation's table looks like this:
Compatibility of reliability QoS policies (ROS 2 Lyrical docs)
| Publisher offers | Subscription requests | Compatible? |
|---|---|---|
| Best effort | Best effort | Yes |
| Best effort | Reliable | No |
| Reliable | Best effort | Yes |
| Reliable | Reliable | Yes |
Here is a typical case. A team building a delivery robot publishes camera frames with the sensor data profile. The docs say this profile uses best effort reliability and a smaller queue size, because fresh readings matter more than complete ones. Someone else writes a logging node with the default profile, which requests reliable. That subscription will never receive a frame. If the camera node offered reliable instead, both a reliable logger and a best-effort viewer could connect.
Rule of thumb from the table
A Reliable publisher is the safe offer: it connects to both Reliable and Best-effort subscriptions. A Best-effort subscription is the safe request: it accepts both kinds of publisher.
Volatile vs transient local, and the ROS 2 version of a latched topic
The durability policy decides what late joiners get. With Transient local, the publisher becomes responsible for persisting samples for late-joining subscriptions. With Volatile, no attempt is made to persist samples.
Compatibility of durability QoS policies (ROS 2 Lyrical docs)
| Publisher | Subscription | Compatible? | Result |
|---|---|---|---|
| Volatile | Volatile | Yes | New messages only |
| Volatile | Transient local | No | No communication |
| Transient local | Volatile | Yes | New messages only |
| Transient local | Transient local | Yes | New and old messages |
This is how ROS 2 replaces ROS 1's latched publishers. The docs say that the transient local durability policy, combined with any depth, gives functionality similar to latching. To get a latched topic that late subscribers can see, both the publisher and the subscriber must agree to use Transient Local. If only the publisher is transient local, a late subscriber that requests volatile connects but receives new messages only. If only the subscriber asks for transient local, nothing connects at all.
Deadline, liveliness and lease duration: the quieter mismatches
Three more policies affect compatibility, and they are easy to miss when a profile is copied from another project:
- Deadline: the expected maximum time between messages on a topic. A publisher with the Default deadline does not satisfy a subscription that requests a duration *x*. A publisher with deadline *x* satisfies a subscription requesting *y* only when *y* is greater than *x*, or the same *x*.
- Liveliness: an Automatic publisher does not satisfy a subscription requesting Manual by topic. The reverse pairing works.
- Lease duration: this follows the same pattern as deadline. Default on the publisher does not satisfy a specific duration on the subscription, and a subscription requesting a shorter lease than the one offered is refused.
For reference, the documentation lists the defaults for publishers and subscriptions: keep last history with a queue size of 10, reliable, volatile, and system default liveliness, with deadline, lifespan and lease durations set to default.
How to find a QoS mismatch in a live system
Incompatible pairs fail without any error, so you have to look for them. The base documents several tools for this:
- Inspect the endpoints. Run ros2 topic info /turtle1/cmd_vel --verbose (or -v). Besides node names and the topic type, the output lists each endpoint's QoS profile: Reliability, History (Depth), Durability, Lifespan, Deadline, Liveliness and lease duration.
- Run the doctor. Since Galactic, ros2 doctor --report includes a QOS COMPATIBILITY LIST. In the release-notes example, a best-effort talker_qos and a reliable listener_qos are reported with the status ERROR: Best effort publisher and reliable subscription.
- Look at the graph. rqt_graph can also detect and report QoS incompatibilities between publishers and subscriptions.
- Check services too. The compatibility rules apply to service servers and clients in the same way. Lyrical adds ros2 service info --verbose, which prints the QoS profiles of request readers and response writers.
- Handle it in code. Publishers can subscribe to the Offered incompatible QoS event and subscriptions to Requested incompatible QoS. Matched events tell you when a compatible connection is made or dropped.
Fixing it from the command line and in rosbag2
During debugging you often need to match the other side's QoS without editing code. ros2 topic pub accepts options such as --qos-reliability, --qos-durability, --qos-depth, --qos-history and --qos-profile. The rosbag2 guide gives two concrete examples. ros2 topic pub -r 0.1 --qos-durability transient_local /talker std_msgs/String "data: Hello World" publishes on a transient local topic, and ros2 topic echo --qos-reliability best_effort /talker std_msgs/String reads a topic as best effort.
Recording has the same constraint. The rosbag2 docs note that only the reliability and durability policies decide whether publishers and subscribers are compatible. Ros2Bag adapts its profile automatically, and you can force a profile with a YAML file passed through --qos-profile-overrides-path. For example: ros2 bag record -a -o my_bag --qos-profile-overrides-path durability_override.yaml, where the file sets durability: transient_local and history: keep_all for /talker.
Why Zenoh is more forgiving
Everything above describes DDS-based middleware, and Fast DDS (rmw_fastrtps_cpp) is the default in Lyrical. Zenoh works differently. The docs describe it as a more lightweight alternative to DDS that keeps Quality of Service features, and add that in Zenoh, there are essentially no incompatible QoS settings. Since Kilted Kaiju, rmw_zenoh_cpp is packaged with the binary releases and is a Tier 1 middleware.
To try it, run export RMW_IMPLEMENTATION=rmw_zenoh_cpp in each terminal and start the router with ros2 run rmw_zenoh_cpp rmw_zenohd. Without the router, nodes cannot discover each other, because multicast discovery is disabled by default in the node's session config. Also note that the docs do not guarantee communication between different RMW implementations, so keep every machine in the system on the same one.
Ask the ROS 2 Lyrical docs directly
The ROS 2 base indexes the official Lyrical Luth documentation: concepts, tutorials, how-to guides, migration notes and release notes. Ask a question such as “If I set up a publisher with Best effort reliability and a subscription that requires Reliable delivery, will they ever connect?” and get an answer with the passage it comes from.
If you prefer to look things up from your editor or a coding agent, the same base can be queried programmatically; see the developer documentation. The base covers ROS 2 core documentation only. Questions about higher-level stacks such as Nav2 costmaps fall outside its scope.
Frequently asked questions
Why is my ROS 2 subscriber not receiving messages when the topic exists?
The most likely cause is an incompatible QoS pair. ROS 2 only connects a publisher and a subscription if no requested policy is stricter than the offered one, and an incompatible pair passes no messages. Check the profiles with ros2 topic info <topic> --verbose or ros2 doctor --report.
Does a reliable publisher work with a best effort subscriber in ROS 2?
Yes. According to the compatibility table in the ROS 2 documentation, a Reliable publisher with a Best effort subscription is compatible. The reverse pairing, a Best effort publisher with a Reliable subscription, is not.
How do I make a latched topic in ROS 2?
Use the Transient local durability policy on both the publisher and the subscription. The docs say transient local, combined with any depth, gives functionality similar to ROS 1 latching, and both sides must agree on it.
What are the default QoS settings in ROS 2?
Publishers and subscriptions default to keep last history with a queue size of 10, reliable reliability, volatile durability and system default liveliness, with deadline, lifespan and lease durations set to default.
Does Zenoh have QoS incompatibilities?
The ROS 2 documentation says that in Zenoh there are essentially no incompatible QoS settings, although Zenoh keeps Quality of Service features. The strict request-vs-offered matching applies to DDS-based middleware.
Get the Kopik newsletter
New knowledge bases, RAG guides and product news. One email every week or two, unsubscribe in one click.
By subscribing you agree to receive our newsletter. We never share your address.